[gtk+] css: Support background-position property



commit e65a2709a30aa703cf83148c7ded8a5de900a429
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Mar 16 22:13:39 2012 +0100

    css: Support background-position property

 gtk/gtkcssstylepropertyimpl.c |  185 +++++++++++++++++++++++++++++++++++++++++
 gtk/gtkthemingbackground.c    |    9 ++-
 2 files changed, 192 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkcssstylepropertyimpl.c b/gtk/gtkcssstylepropertyimpl.c
index f6d4b49..7dd1cf4 100644
--- a/gtk/gtkcssstylepropertyimpl.c
+++ b/gtk/gtkcssstylepropertyimpl.c
@@ -682,6 +682,181 @@ background_size_compute (GtkCssStyleProperty    *property,
   return _gtk_css_value_ref (specified);
 }
 
+static gboolean
+background_position_parse (GtkCssStyleProperty *property,
+			   GValue              *value,
+			   GtkCssParser        *parser,
+			   GFile               *base)
+{
+  static const struct {
+    const char *name;
+    guint       percentage;
+    gboolean    horizontal;
+    gboolean    vertical;
+  } names[] = {
+    { "left",     0, TRUE,  FALSE },
+    { "right",  100, TRUE,  FALSE },
+    { "center",  50, TRUE,  TRUE  },
+    { "top",      0, FALSE, TRUE  },
+    { "bottom", 100, FALSE, TRUE  },
+    { NULL    ,   0, TRUE,  FALSE }, /* used for numbers */
+    { NULL    ,  50, TRUE,  TRUE  }  /* used for no value */
+  };
+  GtkCssBackgroundPosition pos;
+  GtkCssNumber *missing;
+  guint first, second;
+
+  for (first = 0; names[first].name != NULL; first++)
+    {
+      if (_gtk_css_parser_try (parser, names[first].name, TRUE))
+        {
+          if (names[first].horizontal)
+            {
+	      _gtk_css_number_init (&pos.x, names[first].percentage, GTK_CSS_PERCENT);
+              missing = &pos.y;
+            }
+          else
+            {
+	      _gtk_css_number_init (&pos.y, names[first].percentage, GTK_CSS_PERCENT);
+              missing = &pos.x;
+            }
+          break;
+        }
+    }
+  if (names[first].name == NULL)
+    {
+      missing = &pos.y;
+      if (!_gtk_css_parser_read_number (parser,
+					&pos.x,
+					GTK_CSS_PARSE_PERCENT
+					| GTK_CSS_PARSE_LENGTH))
+	return FALSE;
+    }
+
+  for (second = 0; names[second].name != NULL; second++)
+    {
+      if (_gtk_css_parser_try (parser, names[second].name, TRUE))
+        {
+	  _gtk_css_number_init (missing, names[second].percentage, GTK_CSS_PERCENT);
+          break;
+        }
+    }
+
+  if (names[second].name == NULL)
+    {
+      if (_gtk_css_parser_has_number (parser))
+        {
+          if (missing != &pos.y)
+            {
+              _gtk_css_parser_error (parser, "Invalid combination of values");
+              return FALSE;
+            }
+          if (!_gtk_css_parser_read_number (parser,
+                                            missing,
+                                            GTK_CSS_PARSE_PERCENT
+                                            | GTK_CSS_PARSE_LENGTH))
+	    return FALSE;
+        }
+      else
+        {
+          second++;
+          _gtk_css_number_init (missing, 50, GTK_CSS_PERCENT);
+        }
+    }
+  else
+    {
+      if ((names[first].horizontal && !names[second].vertical) ||
+          (!names[first].horizontal && !names[second].horizontal))
+        {
+          _gtk_css_parser_error (parser, "Invalid combination of values");
+          return FALSE;
+        }
+    }
+
+  g_value_set_boxed (value, &pos);
+  return TRUE;
+}
+
+static void
+background_position_print (GtkCssStyleProperty *property,
+			   const GValue        *value,
+			   GString             *string)
+{
+  GtkCssBackgroundPosition *pos = g_value_get_boxed (value);
+  static const GtkCssNumber center = GTK_CSS_NUMBER_INIT (50, GTK_CSS_PERCENT);
+  static const struct {
+    const char *x_name;
+    const char *y_name;
+    GtkCssNumber number;
+  } values[] = { 
+    { "left",   "top",    GTK_CSS_NUMBER_INIT (0,   GTK_CSS_PERCENT) },
+    { "right",  "bottom", GTK_CSS_NUMBER_INIT (100, GTK_CSS_PERCENT) }
+  };
+  guint i;
+
+  if (_gtk_css_number_equal (&pos->x, &center))
+    {
+      if (_gtk_css_number_equal (&pos->y, &center))
+        {
+          g_string_append (string, "center");
+          return;
+        }
+    }
+  else
+    {
+      for (i = 0; i < G_N_ELEMENTS (values); i++)
+        {
+          if (_gtk_css_number_equal (&pos->x, &values[i].number))
+            {
+              g_string_append (string, values[i].x_name);
+              break;
+            }
+        }
+      if (i == G_N_ELEMENTS (values))
+        _gtk_css_number_print (&pos->x, string);
+
+      if (_gtk_css_number_equal (&pos->y, &center))
+        return;
+
+      g_string_append_c (string, ' ');
+    }
+
+  for (i = 0; i < G_N_ELEMENTS (values); i++)
+    {
+      if (_gtk_css_number_equal (&pos->y, &values[i].number))
+        {
+          g_string_append (string, values[i].y_name);
+          break;
+        }
+    }
+  if (i == G_N_ELEMENTS (values))
+    {
+      if (_gtk_css_number_equal (&pos->x, &center))
+        g_string_append (string, "center ");
+      _gtk_css_number_print (&pos->y, string);
+    }
+}
+
+static GtkCssValue *
+background_position_compute (GtkCssStyleProperty    *property,
+			     GtkStyleContext        *context,
+			     GtkCssValue            *specified)
+{
+  GtkCssBackgroundPosition *spos = _gtk_css_value_get_background_position (specified);
+  GtkCssBackgroundPosition cpos;
+  gboolean changed;
+
+  changed = _gtk_css_number_compute (&cpos.x,
+				     &spos->x,
+				     context);
+  changed |= _gtk_css_number_compute (&cpos.y,
+				      &spos->y,
+				      context);
+  if (changed)
+    return _gtk_css_value_new_from_background_position (&cpos);
+  return _gtk_css_value_ref (specified);
+}
+
 /*** REGISTRATION ***/
 
 static GtkSymbolicColor *
@@ -702,6 +877,7 @@ _gtk_css_style_property_init_properties (void)
   GtkCssNumber number;
   GtkSymbolicColor *symbolic;
   GtkCssBackgroundSize default_background_size = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), FALSE, FALSE };
+  GtkCssBackgroundPosition default_background_position = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PERCENT)};
   GtkCssBorderCornerRadius no_corner_radius = { GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX), GTK_CSS_NUMBER_INIT (0, GTK_CSS_PX) };
   GtkBorder border_of_ones = { 1, 1, 1, 1 };
   GtkCssBorderImageRepeat border_image_repeat = { GTK_CSS_REPEAT_STYLE_STRETCH, GTK_CSS_REPEAT_STYLE_STRETCH };
@@ -1054,6 +1230,15 @@ _gtk_css_style_property_init_properties (void)
                                           background_size_print,
                                           background_size_compute,
                                           &default_background_size);
+  gtk_css_style_property_register        ("background-position",
+                                          GTK_TYPE_CSS_BACKGROUND_POSITION,
+                                          GTK_TYPE_CSS_BACKGROUND_POSITION,
+                                          G_TYPE_NONE,
+                                          0,
+                                          background_position_parse,
+                                          background_position_print,
+                                          background_position_compute,
+                                          &default_background_position);
 
   gtk_css_style_property_register        ("border-top-color",
                                           GTK_TYPE_SYMBOLIC_COLOR,
diff --git a/gtk/gtkthemingbackground.c b/gtk/gtkthemingbackground.c
index 161cc5a..89d0acc 100644
--- a/gtk/gtkthemingbackground.c
+++ b/gtk/gtkthemingbackground.c
@@ -162,10 +162,12 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
     {
       GtkCssBackgroundRepeat hrepeat, vrepeat;
       GtkCssBackgroundSize *size;
+      GtkCssBackgroundPosition *pos;
       double image_width, image_height;
       double width, height;
 
       size = _gtk_css_value_get_background_size (_gtk_style_context_peek_property (bg->context, "background-size"));
+      pos = _gtk_css_value_get_background_position (_gtk_style_context_peek_property (bg->context, "background-position"));
       gtk_style_context_get (bg->context, bg->flags,
                              "background-repeat", &hrepeat,
                              NULL);
@@ -199,6 +201,9 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
 
       if (hrepeat == GTK_CSS_BACKGROUND_NO_REPEAT && vrepeat == GTK_CSS_BACKGROUND_NO_REPEAT)
         {
+	  cairo_translate (cr,
+			   _gtk_css_number_get (&pos->x, bg->image_rect.width - image_width),
+			   _gtk_css_number_get (&pos->y, bg->image_rect.height - image_height));
           /* shortcut for normal case */
           _gtk_css_image_draw (bg->image, cr, image_width, image_height);
         }
@@ -276,8 +281,8 @@ _gtk_theming_background_paint (GtkThemingBackground *bg,
           cairo_destroy (cr2);
 
           cairo_set_source_surface (cr, surface,
-                                    /* background-position goes here */
-                                    0, 0);
+				    _gtk_css_number_get (&pos->x, bg->image_rect.width - image_width),
+				    _gtk_css_number_get (&pos->y, bg->image_rect.height - image_height));
           cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
           cairo_surface_destroy (surface);
 



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