[gtk+] css: Turn number values into a virtual type



commit b246d55472cdf7f8589a8cd8627e9dc4aead2fdd
Author: Benjamin Otte <otte redhat com>
Date:   Fri Feb 12 06:25:50 2016 +0100

    css: Turn number values into a virtual type
    
    GtkCssNumberValue is now a base class for numbers.
    
    Actual numbers are now implemented in GtkCssDimensionValue. The name is
    borrowed from the CSS spec, so there.

 gtk/Makefile.am                   |    2 +
 gtk/gtkcssdimensionvalue.c        |  293 +++++++++++++++++++++++++++++++++++++
 gtk/gtkcssdimensionvalueprivate.h |   35 +++++
 gtk/gtkcssnumbervalue.c           |  266 +++-------------------------------
 gtk/gtkcssnumbervalueprivate.h    |   12 ++-
 gtk/gtkcssparser.c                |    9 +-
 6 files changed, 365 insertions(+), 252 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 53b163f..5c2875c 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -391,6 +391,7 @@ gtk_private_h_sources =             \
        gtkcsscornervalueprivate.h      \
        gtkcsscustomgadgetprivate.h     \
        gtkcsscustompropertyprivate.h   \
+       gtkcssdimensionvalueprivate.h   \
        gtkcsseasevalueprivate.h        \
        gtkcssenginevalueprivate.h      \
        gtkcssenumvalueprivate.h        \
@@ -655,6 +656,7 @@ gtk_base_c_sources =                \
        gtkcsscornervalue.c     \
        gtkcsscustomgadget.c    \
        gtkcsscustomproperty.c  \
+       gtkcssdimensionvalue.c  \
        gtkcsseasevalue.c       \
        gtkcssenumvalue.c       \
        gtkcssenginevalue.c     \
diff --git a/gtk/gtkcssdimensionvalue.c b/gtk/gtkcssdimensionvalue.c
new file mode 100644
index 0000000..edf8a6f
--- /dev/null
+++ b/gtk/gtkcssdimensionvalue.c
@@ -0,0 +1,293 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gtkcssdimensionvalueprivate.h"
+
+#include "gtkcssenumvalueprivate.h"
+#include "gtkstylepropertyprivate.h"
+
+#include "fallback-c89.c"
+
+struct _GtkCssValue {
+  GTK_CSS_VALUE_BASE
+  GtkCssUnit unit;
+  double value;
+};
+
+static void
+gtk_css_value_dimension_free (GtkCssValue *value)
+{
+  g_slice_free (GtkCssValue, value);
+}
+
+static double
+get_base_font_size (guint                    property_id,
+                    GtkStyleProviderPrivate *provider,
+                    GtkCssStyle             *style,
+                    GtkCssStyle             *parent_style)
+{
+  if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
+    {
+      if (parent_style)
+        return _gtk_css_number_value_get (gtk_css_style_get_value (parent_style, 
GTK_CSS_PROPERTY_FONT_SIZE), 100);
+      else
+        return _gtk_css_font_size_get_default (provider);
+    }
+
+  return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_SIZE), 100);
+}
+
+static double
+get_dpi (GtkCssStyle *style)
+{
+  return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_DPI), 96);
+}
+
+static GtkCssValue *
+gtk_css_value_dimension_compute (GtkCssValue             *number,
+                              guint                    property_id,
+                              GtkStyleProviderPrivate *provider,
+                              GtkCssStyle             *style,
+                              GtkCssStyle             *parent_style)
+{
+  GtkBorderStyle border_style;
+
+  /* special case according to http://dev.w3.org/csswg/css-backgrounds/#the-border-width */
+  switch (property_id)
+    {
+      case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
+        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
+        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
+          return gtk_css_dimension_value_new (0, GTK_CSS_NUMBER);
+        break;
+      case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
+        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE));
+        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
+          return gtk_css_dimension_value_new (0, GTK_CSS_NUMBER);
+        break;
+      case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
+        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE));
+        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
+          return gtk_css_dimension_value_new (0, GTK_CSS_NUMBER);
+        break;
+      case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
+        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_LEFT_STYLE));
+        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
+          return gtk_css_dimension_value_new (0, GTK_CSS_NUMBER);
+        break;
+      case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
+        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_OUTLINE_STYLE));
+        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
+          return gtk_css_dimension_value_new (0, GTK_CSS_NUMBER);
+        break;
+      default:
+        break;
+    }
+
+  switch (number->unit)
+    {
+    default:
+      g_assert_not_reached();
+      /* fall through */
+    case GTK_CSS_PERCENT:
+      /* percentages for font sizes are computed, other percentages aren't */
+      if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
+        return gtk_css_dimension_value_new (number->value / 100.0 * 
+                                            get_base_font_size (property_id, provider, style, parent_style),
+                                            GTK_CSS_PX);
+    case GTK_CSS_NUMBER:
+    case GTK_CSS_PX:
+    case GTK_CSS_DEG:
+    case GTK_CSS_S:
+      return _gtk_css_value_ref (number);
+    case GTK_CSS_PT:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) / 72.0,
+                                          GTK_CSS_PX);
+    case GTK_CSS_PC:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) / 72.0 * 12.0,
+                                          GTK_CSS_PX);
+    case GTK_CSS_IN:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style),
+                                          GTK_CSS_PX);
+    case GTK_CSS_CM:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) * 0.39370078740157477,
+                                          GTK_CSS_PX);
+    case GTK_CSS_MM:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) * 0.039370078740157477,
+                                          GTK_CSS_PX);
+    case GTK_CSS_EM:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) / 72.0 *
+                                          get_base_font_size (property_id, provider, style, parent_style),
+                                          GTK_CSS_PX);
+    case GTK_CSS_EX:
+      /* for now we pretend ex is half of em */
+      return gtk_css_dimension_value_new (number->value * 0.5 * get_dpi (style) / 72.0 *
+                                          get_base_font_size (property_id, provider, style, parent_style),
+                                          GTK_CSS_PX);
+    case GTK_CSS_REM:
+      return gtk_css_dimension_value_new (number->value * get_dpi (style) / 72.0 *
+                                          _gtk_css_font_size_get_default (provider),
+                                          GTK_CSS_PX);
+    case GTK_CSS_RAD:
+      return gtk_css_dimension_value_new (number->value * 360.0 / (2 * G_PI),
+                                          GTK_CSS_DEG);
+    case GTK_CSS_GRAD:
+      return gtk_css_dimension_value_new (number->value * 360.0 / 400.0,
+                                          GTK_CSS_DEG);
+    case GTK_CSS_TURN:
+      return gtk_css_dimension_value_new (number->value * 360.0,
+                                          GTK_CSS_DEG);
+    case GTK_CSS_MS:
+      return gtk_css_dimension_value_new (number->value / 1000.0,
+                                          GTK_CSS_S);
+    }
+}
+
+static gboolean
+gtk_css_value_dimension_equal (const GtkCssValue *number1,
+                            const GtkCssValue *number2)
+{
+  return number1->unit == number2->unit &&
+         number1->value == number2->value;
+}
+
+static GtkCssValue *
+gtk_css_value_dimension_transition (GtkCssValue *start,
+                                 GtkCssValue *end,
+                                 guint        property_id,
+                                 double       progress)
+{
+  /* FIXME: This needs to be supported at least for percentages,
+   * but for that we kinda need to support calc(5px + 50%) */
+  if (start->unit != end->unit)
+    return NULL;
+
+  return gtk_css_dimension_value_new (start->value + (end->value - start->value) * progress,
+                                      start->unit);
+}
+
+static void
+gtk_css_value_dimension_print (const GtkCssValue *number,
+                            GString           *string)
+{
+  char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+  const char *names[] = {
+    /* [GTK_CSS_NUMBER] = */ "",
+    /* [GTK_CSS_PERCENT] = */ "%",
+    /* [GTK_CSS_PX] = */ "px",
+    /* [GTK_CSS_PT] = */ "pt",
+    /* [GTK_CSS_EM] = */ "em",
+    /* [GTK_CSS_EX] = */ "ex",
+    /* [GTK_CSS_REM] = */ "rem",
+    /* [GTK_CSS_PC] = */ "pc",
+    /* [GTK_CSS_IN] = */ "in",
+    /* [GTK_CSS_CM] = */ "cm",
+    /* [GTK_CSS_MM] = */ "mm",
+    /* [GTK_CSS_RAD] = */ "rad",
+    /* [GTK_CSS_DEG] = */ "deg",
+    /* [GTK_CSS_GRAD] = */ "grad",
+    /* [GTK_CSS_TURN] = */ "turn",
+    /* [GTK_CSS_S] = */ "s",
+    /* [GTK_CSS_MS] = */ "ms",
+  };
+
+  if (isinf (number->value))
+    g_string_append (string, "infinite");
+  else
+    {
+      g_ascii_dtostr (buf, sizeof (buf), number->value);
+      g_string_append (string, buf);
+      if (number->value != 0.0)
+        g_string_append (string, names[number->unit]);
+    }
+}
+
+static double
+gtk_css_value_dimension_get (const GtkCssValue *value,
+                             double             one_hundred_percent)
+{
+  if (value->unit == GTK_CSS_PERCENT)
+    return value->value * one_hundred_percent / 100;
+  else
+    return value->value;
+}
+
+static GtkCssDimension
+gtk_css_value_dimension_get_dimension (const GtkCssValue *value)
+{
+  return gtk_css_unit_get_dimension (value->unit);
+}
+
+static gboolean
+gtk_css_value_dimension_has_percent (const GtkCssValue *value)
+{
+  return gtk_css_unit_get_dimension (value->unit) == GTK_CSS_DIMENSION_PERCENTAGE;
+}
+
+static const GtkCssNumberValueClass GTK_CSS_VALUE_DIMENSION = {
+  {
+    gtk_css_value_dimension_free,
+    gtk_css_value_dimension_compute,
+    gtk_css_value_dimension_equal,
+    gtk_css_value_dimension_transition,
+    gtk_css_value_dimension_print
+  },
+  gtk_css_value_dimension_get,
+  gtk_css_value_dimension_get_dimension,
+  gtk_css_value_dimension_has_percent
+};
+
+GtkCssValue *
+gtk_css_dimension_value_new (double     value,
+                             GtkCssUnit unit)
+{
+  static GtkCssValue number_singletons[] = {
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_NUMBER, 0 },
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_NUMBER, 1 },
+  };
+  static GtkCssValue px_singletons[] = {
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_PX, 0 },
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_PX, 1 },
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_PX, 2 },
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_PX, 3 },
+    { &GTK_CSS_VALUE_DIMENSION.value_class, 1, GTK_CSS_PX, 4 },
+  };
+  GtkCssValue *result;
+
+  if (unit == GTK_CSS_NUMBER && (value == 0 || value == 1))
+    return _gtk_css_value_ref (&number_singletons[(int) value]);
+
+  if (unit == GTK_CSS_PX &&
+      (value == 0 ||
+       value == 1 ||
+       value == 2 ||
+       value == 3 ||
+       value == 4))
+    {
+      return _gtk_css_value_ref (&px_singletons[(int) value]);
+    }
+
+  result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_DIMENSION.value_class);
+  result->unit = unit;
+  result->value = value;
+
+  return result;
+}
+
diff --git a/gtk/gtkcssdimensionvalueprivate.h b/gtk/gtkcssdimensionvalueprivate.h
new file mode 100644
index 0000000..2e08eba
--- /dev/null
+++ b/gtk/gtkcssdimensionvalueprivate.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2012 Red Hat Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Alexander Larsson <alexl gnome org>
+ */
+
+#ifndef __GTK_CSS_DIMENSION_VALUE_PRIVATE_H__
+#define __GTK_CSS_DIMENSION_VALUE_PRIVATE_H__
+
+#include "gtkcssnumbervalueprivate.h"
+
+G_BEGIN_DECLS
+
+GtkCssValue *   gtk_css_dimension_value_new         (double                  value,
+                                                     GtkCssUnit              unit);
+/* This function implemented in gtkcssparser.c */
+GtkCssValue *   gtk_css_dimension_value_parse       (GtkCssParser           *parser,
+                                                     GtkCssNumberParseFlags  flags);
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_DIMENSION_VALUE_PRIVATE_H__ */
diff --git a/gtk/gtkcssnumbervalue.c b/gtk/gtkcssnumbervalue.c
index 86b4c40..a766a63 100644
--- a/gtk/gtkcssnumbervalue.c
+++ b/gtk/gtkcssnumbervalue.c
@@ -1,5 +1,5 @@
 /* GTK - The GIMP Toolkit
- * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2016 Benjamin Otte <otte gnome org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -19,278 +19,52 @@
 
 #include "gtkcssnumbervalueprivate.h"
 
-#include "gtkcssenumvalueprivate.h"
-#include "gtkcssinitialvalueprivate.h"
-#include "gtkstylepropertyprivate.h"
-
-#include "fallback-c89.c"
+#include "gtkcssdimensionvalueprivate.h"
 
 struct _GtkCssValue {
   GTK_CSS_VALUE_BASE
-  GtkCssUnit unit;
-  double value;
 };
 
-static void
-gtk_css_value_number_free (GtkCssValue *value)
-{
-  g_slice_free (GtkCssValue, value);
-}
-
-static double
-get_base_font_size (guint                    property_id,
-                    GtkStyleProviderPrivate *provider,
-                    GtkCssStyle             *style,
-                    GtkCssStyle             *parent_style)
-{
-  if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
-    {
-      if (parent_style)
-        return _gtk_css_number_value_get (gtk_css_style_get_value (parent_style, 
GTK_CSS_PROPERTY_FONT_SIZE), 100);
-      else
-        return _gtk_css_font_size_get_default (provider);
-    }
-
-  return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_FONT_SIZE), 100);
-}
-
-static double
-get_dpi (GtkCssStyle *style)
-{
-  return _gtk_css_number_value_get (gtk_css_style_get_value (style, GTK_CSS_PROPERTY_DPI), 96);
-}
-
-static GtkCssValue *
-gtk_css_value_number_compute (GtkCssValue             *number,
-                              guint                    property_id,
-                              GtkStyleProviderPrivate *provider,
-                              GtkCssStyle             *style,
-                              GtkCssStyle             *parent_style)
-{
-  GtkBorderStyle border_style;
-
-  /* special case according to http://dev.w3.org/csswg/css-backgrounds/#the-border-width */
-  switch (property_id)
-    {
-      case GTK_CSS_PROPERTY_BORDER_TOP_WIDTH:
-        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_TOP_STYLE));
-        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
-          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
-        break;
-      case GTK_CSS_PROPERTY_BORDER_RIGHT_WIDTH:
-        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_RIGHT_STYLE));
-        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
-          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
-        break;
-      case GTK_CSS_PROPERTY_BORDER_BOTTOM_WIDTH:
-        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_BOTTOM_STYLE));
-        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
-          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
-        break;
-      case GTK_CSS_PROPERTY_BORDER_LEFT_WIDTH:
-        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_BORDER_LEFT_STYLE));
-        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
-          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
-        break;
-      case GTK_CSS_PROPERTY_OUTLINE_WIDTH:
-        border_style = _gtk_css_border_style_value_get(gtk_css_style_get_value (style, 
GTK_CSS_PROPERTY_OUTLINE_STYLE));
-        if (border_style == GTK_BORDER_STYLE_NONE || border_style == GTK_BORDER_STYLE_HIDDEN)
-          return _gtk_css_number_value_new (0, GTK_CSS_NUMBER);
-        break;
-      default:
-        break;
-    }
-
-  switch (number->unit)
-    {
-    default:
-      g_assert_not_reached();
-      /* fall through */
-    case GTK_CSS_PERCENT:
-      /* percentages for font sizes are computed, other percentages aren't */
-      if (property_id == GTK_CSS_PROPERTY_FONT_SIZE)
-        return _gtk_css_number_value_new (number->value / 100.0 * 
-                                          get_base_font_size (property_id, provider, style, parent_style),
-                                          GTK_CSS_PX);
-    case GTK_CSS_NUMBER:
-    case GTK_CSS_PX:
-    case GTK_CSS_DEG:
-    case GTK_CSS_S:
-      return _gtk_css_value_ref (number);
-    case GTK_CSS_PT:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) / 72.0,
-                                        GTK_CSS_PX);
-    case GTK_CSS_PC:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) / 72.0 * 12.0,
-                                        GTK_CSS_PX);
-    case GTK_CSS_IN:
-      return _gtk_css_number_value_new (number->value * get_dpi (style),
-                                        GTK_CSS_PX);
-    case GTK_CSS_CM:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) * 0.39370078740157477,
-                                        GTK_CSS_PX);
-    case GTK_CSS_MM:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) * 0.039370078740157477,
-                                        GTK_CSS_PX);
-    case GTK_CSS_EM:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) / 72.0 *
-                                        get_base_font_size (property_id, provider, style, parent_style),
-                                        GTK_CSS_PX);
-    case GTK_CSS_EX:
-      /* for now we pretend ex is half of em */
-      return _gtk_css_number_value_new (number->value * 0.5 * get_dpi (style) / 72.0 *
-                                        get_base_font_size (property_id, provider, style, parent_style),
-                                        GTK_CSS_PX);
-    case GTK_CSS_REM:
-      return _gtk_css_number_value_new (number->value * get_dpi (style) / 72.0 *
-                                        _gtk_css_font_size_get_default (provider),
-                                        GTK_CSS_PX);
-    case GTK_CSS_RAD:
-      return _gtk_css_number_value_new (number->value * 360.0 / (2 * G_PI),
-                                        GTK_CSS_DEG);
-    case GTK_CSS_GRAD:
-      return _gtk_css_number_value_new (number->value * 360.0 / 400.0,
-                                        GTK_CSS_DEG);
-    case GTK_CSS_TURN:
-      return _gtk_css_number_value_new (number->value * 360.0,
-                                        GTK_CSS_DEG);
-    case GTK_CSS_MS:
-      return _gtk_css_number_value_new (number->value / 1000.0,
-                                        GTK_CSS_S);
-    }
-}
-
-static gboolean
-gtk_css_value_number_equal (const GtkCssValue *number1,
-                            const GtkCssValue *number2)
-{
-  return number1->unit == number2->unit &&
-         number1->value == number2->value;
-}
-
-static GtkCssValue *
-gtk_css_value_number_transition (GtkCssValue *start,
-                                 GtkCssValue *end,
-                                 guint        property_id,
-                                 double       progress)
+GtkCssDimension
+gtk_css_number_value_get_dimension (const GtkCssValue *value)
 {
-  /* FIXME: This needs to be supported at least for percentages,
-   * but for that we kinda need to support calc(5px + 50%) */
-  if (start->unit != end->unit)
-    return NULL;
+  GtkCssNumberValueClass *number_value_class = (GtkCssNumberValueClass *) value->class;
 
-  return _gtk_css_number_value_new (start->value + (end->value - start->value) * progress,
-                                    start->unit);
+  return number_value_class->get_dimension (value);
 }
 
-static void
-gtk_css_value_number_print (const GtkCssValue *number,
-                            GString           *string)
+gboolean
+gtk_css_number_value_has_percent (const GtkCssValue *value)
 {
-  char buf[G_ASCII_DTOSTR_BUF_SIZE];
-
-  const char *names[] = {
-    /* [GTK_CSS_NUMBER] = */ "",
-    /* [GTK_CSS_PERCENT] = */ "%",
-    /* [GTK_CSS_PX] = */ "px",
-    /* [GTK_CSS_PT] = */ "pt",
-    /* [GTK_CSS_EM] = */ "em",
-    /* [GTK_CSS_EX] = */ "ex",
-    /* [GTK_CSS_REM] = */ "rem",
-    /* [GTK_CSS_PC] = */ "pc",
-    /* [GTK_CSS_IN] = */ "in",
-    /* [GTK_CSS_CM] = */ "cm",
-    /* [GTK_CSS_MM] = */ "mm",
-    /* [GTK_CSS_RAD] = */ "rad",
-    /* [GTK_CSS_DEG] = */ "deg",
-    /* [GTK_CSS_GRAD] = */ "grad",
-    /* [GTK_CSS_TURN] = */ "turn",
-    /* [GTK_CSS_S] = */ "s",
-    /* [GTK_CSS_MS] = */ "ms",
-  };
+  GtkCssNumberValueClass *number_value_class = (GtkCssNumberValueClass *) value->class;
 
-  if (isinf (number->value))
-    g_string_append (string, "infinite");
-  else
-    {
-      g_ascii_dtostr (buf, sizeof (buf), number->value);
-      g_string_append (string, buf);
-      if (number->value != 0.0)
-        g_string_append (string, names[number->unit]);
-    }
+  return number_value_class->has_percent (value);
 }
 
-static const GtkCssValueClass GTK_CSS_VALUE_NUMBER = {
-  gtk_css_value_number_free,
-  gtk_css_value_number_compute,
-  gtk_css_value_number_equal,
-  gtk_css_value_number_transition,
-  gtk_css_value_number_print
-};
-
 GtkCssValue *
 _gtk_css_number_value_new (double     value,
                            GtkCssUnit unit)
 {
-  static GtkCssValue number_singletons[] = {
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_NUMBER, 0 },
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_NUMBER, 1 },
-  };
-  static GtkCssValue px_singletons[] = {
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 0 },
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 1 },
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 2 },
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 3 },
-    { &GTK_CSS_VALUE_NUMBER, 1, GTK_CSS_PX, 4 },
-  };
-  GtkCssValue *result;
-
-  if (unit == GTK_CSS_NUMBER && (value == 0 || value == 1))
-    return _gtk_css_value_ref (&number_singletons[(int) value]);
-
-  if (unit == GTK_CSS_PX &&
-      (value == 0 ||
-       value == 1 ||
-       value == 2 ||
-       value == 3 ||
-       value == 4))
-    {
-      return _gtk_css_value_ref (&px_singletons[(int) value]);
-    }
-
-  result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_NUMBER);
-  result->unit = unit;
-  result->value = value;
-
-  return result;
+  return gtk_css_dimension_value_new (value, unit);
 }
 
-GtkCssDimension
-gtk_css_number_value_get_dimension (const GtkCssValue *value)
-{
-  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_NUMBER, GTK_CSS_DIMENSION_PERCENTAGE);
-
-  return gtk_css_unit_get_dimension (value->unit);
-}
-
-gboolean
-gtk_css_number_value_has_percent (const GtkCssValue *value)
+GtkCssValue *
+_gtk_css_number_value_parse (GtkCssParser           *parser,
+                             GtkCssNumberParseFlags  flags)
 {
-  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_NUMBER, FALSE);
-
-  return gtk_css_unit_get_dimension (value->unit) == GTK_CSS_DIMENSION_PERCENTAGE;
+  return gtk_css_dimension_value_parse (parser, flags);
 }
 
 double
 _gtk_css_number_value_get (const GtkCssValue *number,
                            double             one_hundred_percent)
 {
+  GtkCssNumberValueClass *number_value_class;
+
   g_return_val_if_fail (number != NULL, 0.0);
-  g_return_val_if_fail (number->class == &GTK_CSS_VALUE_NUMBER, 0.0);
 
-  if (number->unit == GTK_CSS_PERCENT)
-    return number->value * one_hundred_percent / 100;
-  else
-    return number->value;
+  number_value_class = (GtkCssNumberValueClass *) number->class;
+
+  return number_value_class->get (number, one_hundred_percent);
 }
 
diff --git a/gtk/gtkcssnumbervalueprivate.h b/gtk/gtkcssnumbervalueprivate.h
index 454374b..dec0f08 100644
--- a/gtk/gtkcssnumbervalueprivate.h
+++ b/gtk/gtkcssnumbervalueprivate.h
@@ -36,9 +36,19 @@ typedef enum /*< skip >*/ {
   GTK_CSS_PARSE_TIME = (1 << 6)
 } GtkCssNumberParseFlags;
 
+typedef struct _GtkCssNumberValueClass GtkCssNumberValueClass;
+
+struct _GtkCssNumberValueClass {
+  GtkCssValueClass      value_class;
+
+  double                (* get)                     (const GtkCssValue      *value,
+                                                     double                  one_hundred_percent);
+  GtkCssDimension       (* get_dimension)           (const GtkCssValue      *value);
+  gboolean              (* has_percent)             (const GtkCssValue      *value);
+};
+
 GtkCssValue *   _gtk_css_number_value_new           (double                  value,
                                                      GtkCssUnit              unit);
-/* This function implemented in gtkcssparser.c */
 GtkCssValue *   _gtk_css_number_value_parse         (GtkCssParser           *parser,
                                                      GtkCssNumberParseFlags  flags);
 
diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c
index 2c52fb2..86320f3 100644
--- a/gtk/gtkcssparser.c
+++ b/gtk/gtkcssparser.c
@@ -19,8 +19,7 @@
 
 #include "gtkcssparserprivate.h"
 
-#include "gtkcssnumbervalueprivate.h"
-#include "gtkwin32themeprivate.h"
+#include "gtkcssdimensionvalueprivate.h"
 
 #include <errno.h>
 #include <string.h>
@@ -605,8 +604,8 @@ _gtk_css_parser_has_number (GtkCssParser *parser)
 }
 
 GtkCssValue *
-_gtk_css_number_value_parse (GtkCssParser           *parser,
-                             GtkCssNumberParseFlags  flags)
+gtk_css_dimension_value_parse (GtkCssParser           *parser,
+                               GtkCssNumberParseFlags  flags)
 {
   static const struct {
     const char *name;
@@ -721,7 +720,7 @@ _gtk_css_number_value_parse (GtkCssParser           *parser,
 
   _gtk_css_parser_skip_whitespace (parser);
 
-  return _gtk_css_number_value_new (value, unit);
+  return gtk_css_dimension_value_new (value, unit);
 }
 
 /* XXX: we should introduce GtkCssLenght that deals with


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