[gtk+/wip/css: 13/36] css: Add GtkCssNumber



commit 0eb630175ee6721462b40eed02123102906048e8
Author: Benjamin Otte <otte redhat com>
Date:   Fri Jan 13 23:48:42 2012 +0100

    css: Add GtkCssNumber

 gtk/gtkcssparser.c        |  117 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkcssparserprivate.h |   15 +++++-
 gtk/gtkcssstylefuncs.c    |   11 ++++
 gtk/gtkcsstypes.c         |   87 +++++++++++++++++++++++++++++++++
 gtk/gtkcsstypesprivate.h  |   36 ++++++++++++++
 5 files changed, 265 insertions(+), 1 deletions(-)
---
diff --git a/gtk/gtkcssparser.c b/gtk/gtkcssparser.c
index 44b00c3..6c36253 100644
--- a/gtk/gtkcssparser.c
+++ b/gtk/gtkcssparser.c
@@ -529,6 +529,123 @@ _gtk_css_parser_try_double (GtkCssParser *parser,
   return TRUE;
 }
 
+gboolean
+_gtk_css_parser_has_number (GtkCssParser *parser)
+{
+  /* ahem */
+  return strchr ("+-0123456789.", parser->data[0]) != NULL;
+}
+
+gboolean
+_gtk_css_parser_read_number (GtkCssParser           *parser,
+                             GtkCssNumber           *number,
+                             GtkCssNumberParseFlags  flags)
+{
+  static const struct {
+    const char *name;
+    GtkCssUnit unit;
+    GtkCssNumberParseFlags required_flags;
+  } units[] = {
+    { "px", GTK_CSS_PX,      GTK_CSS_PARSE_LENGTH },
+    { "pt", GTK_CSS_PT,      GTK_CSS_PARSE_LENGTH },
+    { "em", GTK_CSS_EM,      GTK_CSS_PARSE_LENGTH },
+    { "ex", GTK_CSS_EX,      GTK_CSS_PARSE_LENGTH },
+    { "pc", GTK_CSS_PC,      GTK_CSS_PARSE_LENGTH },
+    { "in", GTK_CSS_IN,      GTK_CSS_PARSE_LENGTH },
+    { "cm", GTK_CSS_CM,      GTK_CSS_PARSE_LENGTH },
+    { "mm", GTK_CSS_MM,      GTK_CSS_PARSE_LENGTH }
+  };
+  char *end, *unit;
+
+  g_return_val_if_fail (GTK_IS_CSS_PARSER (parser), FALSE);
+  g_return_val_if_fail (number != NULL, FALSE);
+
+  errno = 0;
+  number->unit = GTK_CSS_NUMBER;
+  number->value = g_ascii_strtod (parser->data, &end);
+  if (errno)
+    {
+      _gtk_css_parser_error (parser, "not a number: %s", g_strerror (errno));
+      return FALSE;
+    }
+  if (parser->data == end)
+    {
+      _gtk_css_parser_error (parser, "not a number");
+      return FALSE;
+    }
+
+  parser->data = end;
+
+  if (flags & GTK_CSS_POSITIVE_ONLY &&
+      number->value < 0)
+    {
+      _gtk_css_parser_error (parser, "negative values are not allowed.");
+      return FALSE;
+    }
+
+  unit = _gtk_css_parser_try_ident (parser, FALSE);
+
+  if (unit)
+    {
+      guint i;
+
+      for (i = 0; i < G_N_ELEMENTS (units); i++)
+        {
+          if (flags & units[i].required_flags &&
+              g_ascii_strcasecmp (unit, units[i].name) == 0)
+            break;
+        }
+
+      if (i >= G_N_ELEMENTS (units))
+        {
+          _gtk_css_parser_error (parser, "`%s' is not a valid unit.", unit);
+          g_free (unit);
+          return FALSE;
+        }
+
+      number->unit = units[i].unit;
+      g_free (unit);
+    }
+  else
+    {
+      if ((flags & GTK_CSS_PARSE_PERCENT) &&
+          _gtk_css_parser_try (parser, "%", FALSE))
+        {
+          number->unit = GTK_CSS_PERCENT;
+        }
+      else if (number->value == 0.0)
+        {
+          if (flags & GTK_CSS_PARSE_NUMBER)
+            number->unit = GTK_CSS_NUMBER;
+          else if (flags & GTK_CSS_PARSE_LENGTH)
+            number->unit = GTK_CSS_PX;
+          else
+            number->unit = GTK_CSS_PERCENT;
+        }
+      else if (flags & GTK_CSS_NUMBER_AS_PIXELS)
+        {
+          GError *error = g_error_new_literal (GTK_CSS_PROVIDER_ERROR,
+                                               GTK_CSS_PROVIDER_ERROR_DEPRECATED,
+                                               "Not using units is deprecated. Assuming 'px'.");
+          _gtk_css_parser_take_error (parser, error);
+          number->unit = GTK_CSS_PX;
+        }
+      else if (flags & GTK_CSS_PARSE_NUMBER)
+        {
+          number->unit = GTK_CSS_NUMBER;
+        }
+      else
+        {
+          _gtk_css_parser_error (parser, "Unit is missing.");
+          return FALSE;
+        }
+    }
+
+  _gtk_css_parser_skip_whitespace (parser);
+
+  return TRUE;
+}
+
 /* XXX: we should introduce GtkCssLenght that deals with
  * different kind of units */
 gboolean
diff --git a/gtk/gtkcssparserprivate.h b/gtk/gtkcssparserprivate.h
index d267530..e5661d5 100644
--- a/gtk/gtkcssparserprivate.h
+++ b/gtk/gtkcssparserprivate.h
@@ -20,10 +20,19 @@
 #ifndef __GTK_CSS_PARSER_PRIVATE_H__
 #define __GTK_CSS_PARSER_PRIVATE_H__
 
+#include "gtk/gtkcsstypesprivate.h"
 #include <gtk/gtksymboliccolor.h>
 
 G_BEGIN_DECLS
 
+typedef enum /*< skip >*/ {
+  GTK_CSS_POSITIVE_ONLY = (1 << 0),
+  GTK_CSS_PARSE_PERCENT = (1 << 1),
+  GTK_CSS_PARSE_NUMBER = (1 << 2),
+  GTK_CSS_NUMBER_AS_PIXELS = (1 << 3),
+  GTK_CSS_PARSE_LENGTH = (1 << 4)
+} GtkCssNumberParseFlags;
+
 typedef struct _GtkCssParser GtkCssParser;
 
 typedef void (* GtkCssParserErrorFunc) (GtkCssParser *parser,
@@ -78,7 +87,10 @@ gboolean        _gtk_css_parser_try_enum          (GtkCssParser          *parser
                                                    GType                  enum_type,
                                                    int                   *value);
 
-void            _gtk_css_parser_skip_whitespace   (GtkCssParser          *parser);
+gboolean        _gtk_css_parser_has_number        (GtkCssParser          *parser);
+gboolean        _gtk_css_parser_read_number       (GtkCssParser          *parser,
+                                                   GtkCssNumber          *number,
+                                                   GtkCssNumberParseFlags flags);
 char *          _gtk_css_parser_read_string       (GtkCssParser          *parser);
 char *          _gtk_css_parser_read_value        (GtkCssParser          *parser);
 GtkSymbolicColor *_gtk_css_parser_read_symbolic_color
@@ -86,6 +98,7 @@ GtkSymbolicColor *_gtk_css_parser_read_symbolic_color
 GFile *         _gtk_css_parser_read_url          (GtkCssParser          *parser,
                                                    GFile                 *base);
 
+void            _gtk_css_parser_skip_whitespace   (GtkCssParser          *parser);
 void            _gtk_css_parser_resync            (GtkCssParser          *parser,
                                                    gboolean               sync_at_semicolon,
                                                    char                   terminator);
diff --git a/gtk/gtkcssstylefuncs.c b/gtk/gtkcssstylefuncs.c
index 55291c6..fd72fcb 100644
--- a/gtk/gtkcssstylefuncs.c
+++ b/gtk/gtkcssstylefuncs.c
@@ -1058,6 +1058,13 @@ border_image_repeat_value_print (const GValue *value,
     }
 }
 
+static void
+css_number_print (const GValue *value,
+                  GString      *string)
+{
+  _gtk_css_number_print (g_value_get_boxed (value), string);
+}
+
 static gboolean 
 enum_value_parse (GtkCssParser *parser,
                   GFile        *base,
@@ -1233,6 +1240,10 @@ gtk_css_style_funcs_init (void)
                                 shadow_value_parse,
                                 shadow_value_print,
                                 shadow_value_compute);
+  register_conversion_function (GTK_TYPE_CSS_NUMBER,
+                                NULL,
+                                css_number_print,
+                                NULL);
   register_conversion_function (G_TYPE_ENUM,
                                 enum_value_parse,
                                 enum_value_print,
diff --git a/gtk/gtkcsstypes.c b/gtk/gtkcsstypes.c
index 674fd02..c2929d6 100644
--- a/gtk/gtkcsstypes.c
+++ b/gtk/gtkcsstypes.c
@@ -20,6 +20,7 @@
 #include "config.h"
 
 #include "gtkcsstypesprivate.h"
+#include "gtkstylecontextprivate.h"
 
 #define DEFINE_BOXED_TYPE_WITH_COPY_FUNC(TypeName, type_name) \
 \
@@ -33,3 +34,89 @@ G_DEFINE_BOXED_TYPE (TypeName, type_name, type_name ## _copy, g_free)
 
 DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderCornerRadius, _gtk_css_border_corner_radius)
 DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssBorderImageRepeat, _gtk_css_border_image_repeat)
+DEFINE_BOXED_TYPE_WITH_COPY_FUNC (GtkCssNumber, _gtk_css_number)
+
+void
+_gtk_css_number_init (GtkCssNumber *number,
+                      double        value,
+                      GtkCssUnit    unit)
+{
+  number->value = value;
+  number->unit = unit;
+}
+
+void
+_gtk_css_number_compute (GtkCssNumber       *dest,
+                         const GtkCssNumber *src,
+                         GtkStyleContext    *context)
+{
+  switch (src->unit)
+    {
+    default:
+      g_assert_not_reached();
+      /* fall through */
+    case GTK_CSS_PERCENT:
+    case GTK_CSS_NUMBER:
+    case GTK_CSS_PX:
+      dest->value = src->value;
+      dest->unit = src->unit;
+      break;
+    case GTK_CSS_PT:
+      dest->value = src->value * 96.0 / 72.0;
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_PC:
+      dest->value = src->value * 96.0 / 72.0 * 12.0;
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_IN:
+      dest->value = src->value * 96.0;
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_CM:
+      dest->value = src->value * 96.0 * 0.39370078740157477;
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_MM:
+      dest->value = src->value * 96.0 * 0.039370078740157477;
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_EM:
+      dest->value = src->value * g_value_get_double (_gtk_style_context_peek_property (context, "font-size"));
+      dest->unit = GTK_CSS_PX;
+      break;
+    case GTK_CSS_EX:
+      /* for now we pretend ex is half of em */
+      dest->value = src->value * g_value_get_double (_gtk_style_context_peek_property (context, "font-size"));
+      dest->unit = GTK_CSS_PX;
+      break;
+    }
+}
+
+void
+_gtk_css_number_print (const GtkCssNumber *number,
+                       GString            *string)
+{
+  char buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+  g_return_if_fail (number != NULL);
+  g_return_if_fail (string != NULL);
+
+  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_PC] = */ "pc",
+    /* [GTK_CSS_IN] = */ "in",
+    /* [GTK_CSS_CM] = */ "cm",
+    /* [GTK_CSS_MM] = */ "mm"
+  };
+
+  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]);
+}
diff --git a/gtk/gtkcsstypesprivate.h b/gtk/gtkcsstypesprivate.h
index 244f98d..6422d9a 100644
--- a/gtk/gtkcsstypesprivate.h
+++ b/gtk/gtkcsstypesprivate.h
@@ -21,6 +21,7 @@
 #define __GTK_CSS_TYPES_PRIVATE_H__
 
 #include <glib-object.h>
+#include <gtk/gtkstylecontext.h>
 
 G_BEGIN_DECLS
 
@@ -77,9 +78,31 @@ typedef enum /*< skip >*/ {
   GTK_CSS_BOTTOM_LEFT
 } GtkCssCorner;
 
+typedef enum /*< skip >*/ {
+  /* CSS term: <number> */
+  GTK_CSS_NUMBER,
+  /* CSS term: <percentage> */
+  GTK_CSS_PERCENT,
+  /* CSS term: <length> */
+  GTK_CSS_PX,
+  GTK_CSS_PT,
+  GTK_CSS_EM,
+  GTK_CSS_EX,
+  GTK_CSS_PC,
+  GTK_CSS_IN,
+  GTK_CSS_CM,
+  GTK_CSS_MM
+} GtkCssUnit;
+
+typedef struct _GtkCssNumber GtkCssNumber;
 typedef struct _GtkCssBorderCornerRadius GtkCssBorderCornerRadius;
 typedef struct _GtkCssBorderImageRepeat GtkCssBorderImageRepeat;
 
+struct _GtkCssNumber {
+  gdouble        value;
+  GtkCssUnit     unit;
+};
+
 struct _GtkCssBorderCornerRadius {
   double horizontal;
   double vertical;
@@ -92,9 +115,22 @@ struct _GtkCssBorderImageRepeat {
 
 #define GTK_TYPE_CSS_BORDER_CORNER_RADIUS _gtk_css_border_corner_radius_get_type ()
 #define GTK_TYPE_CSS_BORDER_IMAGE_REPEAT _gtk_css_border_image_repeat_get_type ()
+#define GTK_TYPE_CSS_NUMBER _gtk_css_number_get_type ()
 
 GType           _gtk_css_border_corner_radius_get_type          (void);
 GType           _gtk_css_border_image_repeat_get_type           (void);
+GType           _gtk_css_number_get_type                        (void);
+
+#define GTK_CSS_NUMBER_INIT(_value,_unit) { (_value), (_unit) }
+void            _gtk_css_number_init                            (GtkCssNumber       *number,
+                                                                 double              value,
+                                                                 GtkCssUnit          unit);
+void            _gtk_css_number_compute                         (GtkCssNumber       *dest,
+                                                                 const GtkCssNumber *src,
+                                                                 GtkStyleContext    *context);
+void            _gtk_css_number_print                           (const GtkCssNumber *number,
+                                                                 GString            *string);
+
 
 G_END_DECLS
 



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