[gtk+/wip/cssvalue: 118/164] cssvalue: Add a border value



commit d2f00cac5af043ed517a96d3bf5f0cce252ef4a1
Author: Benjamin Otte <otte redhat com>
Date:   Wed Apr 4 16:15:41 2012 +0200

    cssvalue: Add a border value
    
    .. and parse border-image-slice with it.

 gtk/Makefile.am                   |    2 +
 gtk/gtkborderimage.c              |   12 +-
 gtk/gtkborderimageprivate.h       |    2 +-
 gtk/gtkcssbordervalue.c           |  235 +++++++++++++++++++++++++++++++++++++
 gtk/gtkcssbordervalueprivate.h    |   48 ++++++++
 gtk/gtkcssshorthandpropertyimpl.c |   16 ++-
 gtk/gtkcssstylepropertyimpl.c     |   75 +++++++++----
 gtk/gtkcssvalue.c                 |   13 ++
 gtk/gtkcssvalueprivate.h          |    2 +
 9 files changed, 372 insertions(+), 33 deletions(-)
---
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 01ea4ca..062b999 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -425,6 +425,7 @@ gtk_private_h_sources =		\
 	gtkcontainerprivate.h   \
 	gtkcssarrayvalueprivate.h	\
 	gtkcssbgsizevalueprivate.h	\
+	gtkcssbordervalueprivate.h	\
 	gtkcsscomputedvaluesprivate.h \
 	gtkcsscornervalueprivate.h	\
 	gtkcsscustompropertyprivate.h \
@@ -638,6 +639,7 @@ gtk_base_c_sources = 		\
 	gtkcontainer.c		\
 	gtkcssarrayvalue.c	\
 	gtkcssbgsizevalue.c	\
+	gtkcssbordervalue.c	\
 	gtkcsscomputedvalues.c	\
 	gtkcsscornervalue.c	\
 	gtkcsscustomproperty.c	\
diff --git a/gtk/gtkborderimage.c b/gtk/gtkborderimage.c
index 9347860..f75d7e0 100644
--- a/gtk/gtkborderimage.c
+++ b/gtk/gtkborderimage.c
@@ -25,7 +25,9 @@
 #include <math.h>
 
 #include "gtkborderimageprivate.h"
+#include "gtkcssbordervalueprivate.h"
 #include "gtkcssimagevalueprivate.h"
+#include "gtkcssnumbervalueprivate.h"
 #include "gtkcssrepeatvalueprivate.h"
 #include "gtkstylepropertiesprivate.h"
 #include "gtkthemingengineprivate.h"
@@ -45,7 +47,7 @@ _gtk_border_image_init (GtkBorderImage   *image,
   if (image->source == NULL)
     return FALSE;
 
-  image->slice = *(GtkBorder *) _gtk_css_value_get_boxed (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE));
+  image->slice = _gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE);
   width = _gtk_css_value_get_boxed (_gtk_theming_engine_peek_property (engine, GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH));
   if (width)
     {
@@ -254,12 +256,12 @@ _gtk_border_image_render (GtkBorderImage   *image,
 
   gtk_border_image_compute_slice_size (horizontal_slice,
                                        source_width, 
-                                       image->slice.left,
-                                       image->slice.right);
+                                       _gtk_css_number_value_get (_gtk_css_border_value_get_left (image->slice), source_width),
+                                       _gtk_css_number_value_get (_gtk_css_border_value_get_right (image->slice), source_width));
   gtk_border_image_compute_slice_size (vertical_slice,
                                        source_height, 
-                                       image->slice.top,
-                                       image->slice.bottom);
+                                       _gtk_css_number_value_get (_gtk_css_border_value_get_top (image->slice), source_height),
+                                       _gtk_css_number_value_get (_gtk_css_border_value_get_bottom (image->slice), source_height));
   gtk_border_image_compute_border_size (horizontal_border,
                                         x,
                                         width,
diff --git a/gtk/gtkborderimageprivate.h b/gtk/gtkborderimageprivate.h
index c77de04..f57149c 100644
--- a/gtk/gtkborderimageprivate.h
+++ b/gtk/gtkborderimageprivate.h
@@ -34,7 +34,7 @@ typedef struct _GtkBorderImage GtkBorderImage;
 struct _GtkBorderImage {
   GtkCssImage *source;
 
-  GtkBorder slice;
+  GtkCssValue *slice;
   gboolean has_width;
   GtkBorder width;
   GtkCssValue *repeat;
diff --git a/gtk/gtkcssbordervalue.c b/gtk/gtkcssbordervalue.c
new file mode 100644
index 0000000..92ae98a
--- /dev/null
+++ b/gtk/gtkcssbordervalue.c
@@ -0,0 +1,235 @@
+/* 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 "gtkcssbordervalueprivate.h"
+
+#include "gtkcssnumbervalueprivate.h"
+
+struct _GtkCssValue {
+  GTK_CSS_VALUE_BASE
+  guint fill :1;
+  GtkCssValue *values[4];
+};
+
+static void
+gtk_css_value_border_free (GtkCssValue *value)
+{
+  guint i;
+
+  for (i = 0; i < 4; i++)
+    {
+      if (value->values[i])
+        _gtk_css_value_unref (value->values[i]);
+    }
+
+  g_slice_free (GtkCssValue, value);
+}
+
+static gboolean
+gtk_css_value_border_equal (const GtkCssValue *value1,
+                            const GtkCssValue *value2)
+{
+  guint i;
+
+  if (value1->fill != value2->fill)
+    return FALSE;
+
+  for (i = 0; i < 4; i++)
+    {
+      if (!_gtk_css_value_equal0 (value1->values[i], value2->values[i]))
+        return FALSE;
+    }
+
+  return TRUE;
+}
+
+static GtkCssValue *
+gtk_css_value_border_transition (GtkCssValue *start,
+                                 GtkCssValue *end,
+                                 double       progress)
+{
+  return NULL;
+}
+
+static void
+gtk_css_value_border_print (const GtkCssValue *value,
+                            GString           *string)
+{
+  guint i, n;
+
+  if (!_gtk_css_value_equal0 (value->values[GTK_CSS_RIGHT], value->values[GTK_CSS_LEFT]))
+    n = 4;
+  else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_BOTTOM]))
+    n = 3;
+  else if (!_gtk_css_value_equal0 (value->values[GTK_CSS_TOP], value->values[GTK_CSS_RIGHT]))
+    n = 2;
+  else
+    n = 1;
+
+  for (i = 0; i < n; i++)
+    {
+      if (i > 0)
+        g_string_append_c (string, ' ');
+
+      if (value->values[i] == NULL)
+        g_string_append (string, "auto");
+      else
+        _gtk_css_value_print (value->values[i], string);
+    }
+
+  if (value->fill)
+    g_string_append (string, " fill");
+}
+
+static const GtkCssValueClass GTK_CSS_VALUE_BORDER = {
+  gtk_css_value_border_free,
+  gtk_css_value_border_equal,
+  gtk_css_value_border_transition,
+  gtk_css_value_border_print
+};
+
+GtkCssValue *
+_gtk_css_border_value_new (GtkCssValue *top,
+                           GtkCssValue *right,
+                           GtkCssValue *bottom,
+                           GtkCssValue *left)
+{
+  GtkCssValue *result;
+
+  result = _gtk_css_value_new (GtkCssValue, &GTK_CSS_VALUE_BORDER);
+  result->values[GTK_CSS_TOP] = top;
+  result->values[GTK_CSS_RIGHT] = right;
+  result->values[GTK_CSS_BOTTOM] = bottom;
+  result->values[GTK_CSS_LEFT] = left;
+
+  return result;
+}
+
+GtkCssValue *
+_gtk_css_border_value_parse (GtkCssParser           *parser,
+                             GtkCssNumberParseFlags  flags,
+                             gboolean                allow_auto,
+                             gboolean                allow_fill)
+{
+  GtkCssValue *result;
+  guint i;
+
+  result = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
+
+  if (allow_fill)
+    result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
+
+  for (i = 0; i < 4; i++)
+    {
+      if (allow_auto && _gtk_css_parser_try (parser, "auto", TRUE))
+        continue;
+
+      if (!_gtk_css_parser_has_number (parser))
+        break;
+
+      result->values[i] = _gtk_css_number_value_parse (parser, flags);
+      if (result->values[i] == NULL)
+        {
+          _gtk_css_value_unref (result);
+          return NULL;
+        }
+    }
+
+  if (i == 0)
+    {
+      _gtk_css_parser_error (parser, "Expected a number");
+      _gtk_css_value_unref (result);
+      return NULL;
+    }
+
+  if (allow_fill && !result->fill)
+    result->fill = _gtk_css_parser_try (parser, "fill", TRUE);
+
+  for (; i < 4; i++)
+    {
+      if (result->values[(i - 1) >> 1])
+        result->values[i] = _gtk_css_value_ref (result->values[(i - 1) >> 1]);
+    }
+
+  return result;
+}
+
+GtkCssValue *
+_gtk_css_border_value_get_top (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
+
+  return value->values[GTK_CSS_TOP];
+}
+
+GtkCssValue *
+_gtk_css_border_value_get_right (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
+
+  return value->values[GTK_CSS_RIGHT];
+}
+
+GtkCssValue *
+_gtk_css_border_value_get_bottom (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
+
+  return value->values[GTK_CSS_BOTTOM];
+}
+
+GtkCssValue *
+_gtk_css_border_value_get_left (const GtkCssValue *value)
+{
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
+
+  return value->values[GTK_CSS_LEFT];
+}
+
+GtkCssValue *
+_gtk_css_border_value_compute (GtkCssValue     *value,
+                               GtkStyleContext *context)
+{
+  GtkCssValue *computed;
+  gboolean changed = FALSE;
+  guint i;
+
+  g_return_val_if_fail (value->class == &GTK_CSS_VALUE_BORDER, NULL);
+
+  computed = _gtk_css_border_value_new (NULL, NULL, NULL, NULL);
+  computed->fill = value->fill;
+
+  for (i = 0; i < 4; i++)
+    {
+      if (value->values[i])
+        {
+          computed->values[i] = _gtk_css_number_value_compute (value->values[i], context);
+          changed |= (computed->values[i] != value->values[i]);
+        }
+    }
+
+  if (!changed)
+    {
+      _gtk_css_value_unref (computed);
+      return _gtk_css_value_ref (value);
+    }
+
+  return computed;
+}
+
diff --git a/gtk/gtkcssbordervalueprivate.h b/gtk/gtkcssbordervalueprivate.h
new file mode 100644
index 0000000..458462b
--- /dev/null
+++ b/gtk/gtkcssbordervalueprivate.h
@@ -0,0 +1,48 @@
+/*
+ * 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_BORDER_VALUE_PRIVATE_H__
+#define __GTK_CSS_BORDER_VALUE_PRIVATE_H__
+
+#include "gtkcssparserprivate.h"
+#include "gtkcssvalueprivate.h"
+
+G_BEGIN_DECLS
+
+GtkCssValue *   _gtk_css_border_value_new           (GtkCssValue            *top,
+                                                     GtkCssValue            *right,
+                                                     GtkCssValue            *bottom,
+                                                     GtkCssValue            *left);
+GtkCssValue *   _gtk_css_border_value_parse         (GtkCssParser           *parser,
+                                                     GtkCssNumberParseFlags  flags,
+                                                     gboolean                allow_auto,
+                                                     gboolean                allow_fill);
+
+GtkCssValue *   _gtk_css_border_value_get_top       (const GtkCssValue      *value);
+GtkCssValue *   _gtk_css_border_value_get_right     (const GtkCssValue      *value);
+GtkCssValue *   _gtk_css_border_value_get_bottom    (const GtkCssValue      *value);
+GtkCssValue *   _gtk_css_border_value_get_left      (const GtkCssValue      *value);
+
+GtkCssValue *   _gtk_css_border_value_compute       (GtkCssValue            *border,
+                                                     GtkStyleContext        *context);
+
+
+G_END_DECLS
+
+#endif /* __GTK_CSS_BORDER_VALUE_PRIVATE_H__ */
diff --git a/gtk/gtkcssshorthandpropertyimpl.c b/gtk/gtkcssshorthandpropertyimpl.c
index f93859c..3a26a28 100644
--- a/gtk/gtkcssshorthandpropertyimpl.c
+++ b/gtk/gtkcssshorthandpropertyimpl.c
@@ -25,6 +25,7 @@
 #include <math.h>
 
 #include "gtkcssarrayvalueprivate.h"
+#include "gtkcssbordervalueprivate.h"
 #include "gtkcsscornervalueprivate.h"
 #include "gtkcssenumvalueprivate.h"
 #include "gtkcssimageprivate.h"
@@ -304,16 +305,19 @@ parse_border_image (GtkCssShorthandProperty  *shorthand,
         }
       else if (values[1] == NULL)
         {
-          GValue value = G_VALUE_INIT;
-
-          g_value_init (&value, GTK_TYPE_BORDER);
-          if (!_gtk_css_style_parse_value (&value, parser, base))
+          values[1] = _gtk_css_border_value_parse (parser,
+                                                   GTK_CSS_PARSE_PERCENT
+                                                   | GTK_CSS_PARSE_NUMBER
+                                                   | GTK_CSS_POSITIVE_ONLY,
+                                                   FALSE,
+                                                   TRUE);
+          if (values[1] == NULL)
             return FALSE;
-          values[1] = _gtk_css_value_new_from_gvalue (&value);
-          g_value_unset (&value);
 
           if (_gtk_css_parser_try (parser, "/", TRUE))
             {
+              GValue value = G_VALUE_INIT;
+
               g_value_init (&value, GTK_TYPE_BORDER);
               if (!_gtk_css_style_parse_value (&value, parser, base))
                 return FALSE;
diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c
index 644388c..a5861ee 100644
--- a/gtk/gtkcssstylepropertyimpl.c
+++ b/gtk/gtkcssstylepropertyimpl.c
@@ -42,6 +42,7 @@
 #include "gtkbindings.h"
 #include "gtkcssarrayvalueprivate.h"
 #include "gtkcssbgsizevalueprivate.h"
+#include "gtkcssbordervalueprivate.h"
 #include "gtkcsscornervalueprivate.h"
 #include "gtkcsseasevalueprivate.h"
 #include "gtkcssenginevalueprivate.h"
@@ -159,6 +160,38 @@ assign_length_from_double (GtkCssStyleProperty *property,
   return _gtk_css_number_value_new (g_value_get_double (value), GTK_CSS_PX);
 }
 
+static void
+query_border (GtkCssStyleProperty *property,
+              const GtkCssValue   *css_value,
+              GValue              *value)
+{
+  GtkBorder border;
+
+  g_value_init (value, GTK_TYPE_BORDER);
+  
+  border.top = round (_gtk_css_number_value_get (_gtk_css_border_value_get_top (css_value), 100));
+  border.right = round (_gtk_css_number_value_get (_gtk_css_border_value_get_right (css_value), 100));
+  border.bottom = round (_gtk_css_number_value_get (_gtk_css_border_value_get_bottom (css_value), 100));
+  border.left = round (_gtk_css_number_value_get (_gtk_css_border_value_get_left (css_value), 100));
+
+  g_value_set_boxed (value, &border);
+}
+
+static GtkCssValue *
+assign_border (GtkCssStyleProperty *property,
+               const GValue        *value)
+{
+  const GtkBorder *border = g_value_get_boxed (value);
+
+  if (border == NULL)
+    return _gtk_css_value_ref (_gtk_css_style_property_get_initial_value (property));
+  else
+    return _gtk_css_border_value_new (_gtk_css_number_value_new (border->top, GTK_CSS_PX),
+                                      _gtk_css_number_value_new (border->right, GTK_CSS_PX),
+                                      _gtk_css_number_value_new (border->bottom, GTK_CSS_PX),
+                                      _gtk_css_number_value_new (border->left, GTK_CSS_PX));
+}
+
 static GtkCssValue *
 color_parse (GtkCssStyleProperty *property,
              GtkCssParser        *parser,
@@ -683,20 +716,12 @@ border_image_slice_parse (GtkCssStyleProperty *property,
                           GtkCssParser        *parser,
                           GFile               *base)
 {
-  GValue value = G_VALUE_INIT;
-  GtkCssValue *result;
-
-  g_value_init (&value, GTK_TYPE_BORDER);
-  if (!_gtk_css_style_parse_value (&value, parser, base))
-    {
-      g_value_unset (&value);
-      return NULL;
-    }
-
-  result = _gtk_css_value_new_from_gvalue (&value);
-  g_value_unset (&value);
-
-  return result;
+  return _gtk_css_border_value_parse (parser,
+                                      GTK_CSS_PARSE_PERCENT
+                                      | GTK_CSS_PARSE_NUMBER
+                                      | GTK_CSS_POSITIVE_ONLY,
+                                      FALSE,
+                                      TRUE);
 }
 
 static GtkCssValue *
@@ -721,6 +746,14 @@ border_image_width_parse (GtkCssStyleProperty *property,
 }
 
 static GtkCssValue *
+compute_border (GtkCssStyleProperty *property,
+                GtkStyleContext     *context,
+                GtkCssValue         *specified)
+{
+  return _gtk_css_border_value_compute (specified, context);
+}
+
+static GtkCssValue *
 transition_property_parse_one (GtkCssParser *parser)
 {
   char *name;
@@ -942,8 +975,6 @@ gtk_symbolic_color_new_rgba (double red,
 void
 _gtk_css_style_property_init_properties (void)
 {
-  GtkBorder border_of_ones = { 1, 1, 1, 1 };
-
   /* Initialize "color" and "font-size" first,
    * so that when computing values later they are
    * done first. That way, 'currentColor' and font
@@ -1492,18 +1523,20 @@ _gtk_css_style_property_init_properties (void)
                                           _gtk_css_border_repeat_value_new (GTK_CSS_REPEAT_STYLE_STRETCH,
                                                                             GTK_CSS_REPEAT_STYLE_STRETCH));
 
-  /* XXX: The initial value is wrong, it should be 100% */
   gtk_css_style_property_register        ("border-image-slice",
                                           GTK_CSS_PROPERTY_BORDER_IMAGE_SLICE,
                                           GTK_TYPE_BORDER,
                                           0,
                                           border_image_slice_parse,
                                           NULL,
+                                          compute_border,
+                                          query_border,
+                                          assign_border,
                                           NULL,
-                                          query_simple,
-                                          assign_simple,
-                                          NULL,
-                                          _gtk_css_value_new_from_boxed (GTK_TYPE_BORDER, &border_of_ones));
+                                          _gtk_css_border_value_new (_gtk_css_number_value_new (100, GTK_CSS_PERCENT),
+                                                                     _gtk_css_number_value_new (100, GTK_CSS_PERCENT),
+                                                                     _gtk_css_number_value_new (100, GTK_CSS_PERCENT),
+                                                                     _gtk_css_number_value_new (100, GTK_CSS_PERCENT)));
   gtk_css_style_property_register        ("border-image-width",
                                           GTK_CSS_PROPERTY_BORDER_IMAGE_WIDTH,
                                           GTK_TYPE_BORDER,
diff --git a/gtk/gtkcssvalue.c b/gtk/gtkcssvalue.c
index 80ccd54..477d7b1 100644
--- a/gtk/gtkcssvalue.c
+++ b/gtk/gtkcssvalue.c
@@ -349,6 +349,19 @@ _gtk_css_value_equal (const GtkCssValue *value1,
   return value1->class->equal (value1, value2);
 }
 
+gboolean
+_gtk_css_value_equal0 (const GtkCssValue *value1,
+                       const GtkCssValue *value2)
+{
+  if (value1 == NULL && value2 == NULL)
+    return TRUE;
+
+  if (value1 == NULL || value2 == NULL)
+    return FALSE;
+
+  return _gtk_css_value_equal (value1, value2);
+}
+
 GtkCssValue *
 _gtk_css_value_transition (GtkCssValue *start,
                            GtkCssValue *end,
diff --git a/gtk/gtkcssvalueprivate.h b/gtk/gtkcssvalueprivate.h
index 0dc1f9a..66453cc 100644
--- a/gtk/gtkcssvalueprivate.h
+++ b/gtk/gtkcssvalueprivate.h
@@ -66,6 +66,8 @@ void         _gtk_css_value_unref                     (GtkCssValue
 
 gboolean     _gtk_css_value_equal                     (const GtkCssValue          *value1,
                                                        const GtkCssValue          *value2);
+gboolean     _gtk_css_value_equal0                    (const GtkCssValue          *value1,
+                                                       const GtkCssValue          *value2);
 GtkCssValue *_gtk_css_value_transition                (GtkCssValue                *start,
                                                        GtkCssValue                *end,
                                                        double                      progress);



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