[goocanvas/new-api: 3/7] removed cascading style sheets, and used simple style objects instead



commit 99351afa9216330e175658f35c27b21ab9ba6836
Author: Damon Chaplin <damon gnome org>
Date:   Thu Jun 24 14:53:14 2010 +0100

    removed cascading style sheets, and used simple style objects instead

 demo/demo-item.c          |    2 +-
 demo/demo-large-line.c    |    2 +-
 demo/demo.c               |   14 +-
 demo/scalability-demo.c   |  155 +++++----
 src/goocanvasgrid.c       |    8 +-
 src/goocanvasgroup.c      |    2 -
 src/goocanvasimage.c      |    2 +-
 src/goocanvasitem.c       |   40 --
 src/goocanvasitem.h       |   11 +-
 src/goocanvasitemsimple.c |  322 ++++++++---------
 src/goocanvasitemsimple.h |   12 +-
 src/goocanvaspath.c       |    2 +-
 src/goocanvaspolyline.c   |    6 +-
 src/goocanvasstyle.c      |  861 +++++++++++++++++++++------------------------
 src/goocanvasstyle.h      |   88 ++----
 src/goocanvastable.c      |    9 +-
 src/goocanvastext.c       |   90 ++++--
 src/goocanvasutils.c      |   17 +-
 18 files changed, 763 insertions(+), 880 deletions(-)
---
diff --git a/demo/demo-item.c b/demo/demo-item.c
index a057a14..027911d 100644
--- a/demo/demo-item.c
+++ b/demo/demo-item.c
@@ -99,7 +99,7 @@ goo_demo_item_paint (GooCanvasItemSimple   *simple,
 		 demo_item->y + demo_item->height);
   cairo_line_to (cr, demo_item->x + demo_item->width, demo_item->y);
   cairo_close_path (cr);
-  goo_canvas_style_set_fill_options (simple->style, cr);
+  goo_canvas_item_simple_set_fill_options (simple, cr);
   cairo_fill (cr);
 }
 
diff --git a/demo/demo-large-line.c b/demo/demo-large-line.c
index 8f109f5..8b1e9b3 100644
--- a/demo/demo-large-line.c
+++ b/demo/demo-large-line.c
@@ -210,7 +210,7 @@ goo_demo_large_line_paint (GooCanvasItemSimple   *simple,
   GooDemoLargeLine *item = (GooDemoLargeLine*) simple;
   gdouble line_width;
 
-  goo_canvas_style_set_stroke_options (simple->style, cr);
+  goo_canvas_item_simple_set_stroke_options (simple, cr);
   line_width = goo_canvas_item_simple_get_line_width (simple);
   paint_large_line (item, cr, bounds, line_width,
 		    item->x1, item->y1, item->x2, item->y2);
diff --git a/demo/demo.c b/demo/demo.c
index 2c44e18..8977309 100644
--- a/demo/demo.c
+++ b/demo/demo.c
@@ -948,16 +948,19 @@ static void
 polish_diamond (GooCanvasItem *root)
 {
   GooCanvasItem *group, *item;
+  GooCanvasStyle *style;
   int i, j;
   double a, x1, y1, x2, y2;
 
-  group = goo_canvas_group_new (root,
-				"line-width", 1.0,
-				"line-cap", CAIRO_LINE_CAP_ROUND,
-				NULL);
+  group = goo_canvas_group_new (root, NULL);
   goo_canvas_item_translate (group, 270, 230);
   setup_item_signals (group);
 
+  style = g_object_new (GOO_TYPE_CANVAS_STYLE,
+			"line-width", 1.0,
+			"line-cap", CAIRO_LINE_CAP_ROUND,
+			NULL);
+
   for (i = 0; i < VERTICES; i++) {
     a = 2.0 * M_PI * i / VERTICES;
     x1 = RADIUS * cos (a);
@@ -968,8 +971,11 @@ polish_diamond (GooCanvasItem *root)
       x2 = RADIUS * cos (a);
       y2 = RADIUS * sin (a);
       item = goo_canvas_polyline_new_line (group, x1, y1, x2, y2, NULL);
+      goo_canvas_item_simple_set_style ((GooCanvasItemSimple*) item, style);
     }
   }
+
+  g_object_unref (style);
 }
 
 
diff --git a/demo/scalability-demo.c b/demo/scalability-demo.c
index bbf4a1f..913a996 100644
--- a/demo/scalability-demo.c
+++ b/demo/scalability-demo.c
@@ -1,3 +1,4 @@
+#include <math.h>
 #include <stdlib.h>
 #include <goocanvas.h>
 
@@ -47,6 +48,12 @@ double total_width, total_height;
 double left_offset, top_offset;
 char ids[N_TOTAL_ID_ITEMS][MAX_ID_LEN];
 
+GdkPixbuf *pixbuf = NULL;
+cairo_pattern_t *pattern = NULL;
+double item_width, item_height;
+double cell_width, cell_height;
+double group_width, group_height;
+
 static clock_t start;
 
 static gboolean
@@ -75,72 +82,59 @@ on_motion_notify (GooCanvasItem *item,
 
 
 static void
+init_ids (void)
+{
+  int group_i, group_j, i, j;
+  int id_item_num = 0;;
+	
+  for (group_i = 0; group_i < N_GROUP_COLS; group_i++)
+    {
+      for (group_j = 0; group_j < N_GROUP_ROWS; group_j++)
+	{
+	  double group_x = left_offset + (group_i * group_width);
+	  double group_y = top_offset + (group_j * group_height);
+
+	  for (i = 0; i < N_COLS; i++)
+	    {
+	      for (j = 0; j < N_ROWS; j++)
+		{
+		  double item_x = (i * cell_width) + PADDING;
+		  double item_y = (j * cell_height) + PADDING;
+
+		  sprintf (ids[id_item_num++], "%.10g, %.10g",
+			   group_x + item_x, group_y + item_y);
+		}
+	    }
+	}
+    }
+}
+
+
+static void
 setup_canvas (GtkWidget *canvas)
 {
   GooCanvasItem *root, *group, *item;
-  GdkPixbuf *pixbuf = NULL;
-  cairo_pattern_t *pattern = NULL;
   int group_i, group_j, i, j;
-  double item_width, item_height;
-  double cell_width, cell_height;
-  double group_width, group_height;
   int total_items = 0, id_item_num = 0;;
-  GdkColor color = { 0, 0, 0, 0, };
   GooCanvasStyle *style, *style2;
-  GValue tmpval = { 0 };
+  PangoFontDescription *font_desc;
+  cairo_matrix_t item_matrix;
+  GQuark id_quark = g_quark_from_static_string ("id");
 
   root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
 
   g_signal_connect (root, "motion_notify_event",
 		    G_CALLBACK (on_motion_notify), NULL);
 
-  g_object_set (G_OBJECT (root),
-		"font", "Sans 8",
-		NULL);
-
-#ifdef USE_PIXMAP
-  pixbuf = gdk_pixbuf_new_from_file("toroid.png", NULL);
-  item_width = gdk_pixbuf_get_width (pixbuf);
-  item_height = gdk_pixbuf_get_height (pixbuf);
-  pattern = goo_canvas_cairo_pattern_from_pixbuf (pixbuf);
-#else
-  pixbuf = NULL;
-  item_width = ITEM_WIDTH;
-  item_height = 19;
-#endif
-	
-  cell_width = item_width + PADDING * 2;
-  cell_height = item_height + PADDING * 2;
-
-  group_width = N_COLS * cell_width;
-  group_height = N_ROWS * cell_height;
-
-  total_width = N_GROUP_COLS * group_width;
-  total_height = N_GROUP_ROWS * group_height;
+  font_desc = pango_font_description_from_string ("Sans 8");
 
-  /* We use -ve offsets to test if -ve coords are handled correctly. */
-  left_offset = -total_width / 2;
-  top_offset = -total_height / 2;
+  style = g_object_new (GOO_TYPE_CANVAS_STYLE,
+			"fill-color", "mediumseagreen",
+			NULL);
 
-  style = goo_canvas_style_new ();
-  gdk_color_parse ("mediumseagreen", &color);
-  pattern = cairo_pattern_create_rgb (color.red / 65535.0,
-				      color.green / 65535.0,
-				      color.blue / 65535.0);
-  g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-  g_value_take_boxed (&tmpval, pattern);
-  goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, &tmpval);
-  g_value_unset (&tmpval);
-
-  style2 = goo_canvas_style_new ();
-  gdk_color_parse ("steelblue", &color);
-  pattern = cairo_pattern_create_rgb (color.red / 65535.0,
-				      color.green / 65535.0,
-				      color.blue / 65535.0);
-  g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-  g_value_take_boxed (&tmpval, pattern);
-  goo_canvas_style_set_property (style2, goo_canvas_style_fill_pattern_id, &tmpval);
-  g_value_unset (&tmpval);
+  style2 = g_object_new (GOO_TYPE_CANVAS_STYLE,
+			 "fill-color", "steelblue",
+			 NULL);
 
   for (group_i = 0; group_i < N_GROUP_COLS; group_i++)
     {
@@ -160,14 +154,11 @@ setup_canvas (GtkWidget *canvas)
 		  double item_x = (i * cell_width) + PADDING;
 		  double item_y = (j * cell_height) + PADDING;
 #ifdef ROTATE
-		  double rotation = i % 10 * 2;
+		  double rotation = (i % 10 * 2) * M_PI / 180;
 		  double rotation_x = item_x + item_width / 2;
 		  double rotation_y = item_y + item_height / 2;
 #endif
 
-		  sprintf (ids[id_item_num], "%.10g, %.10g",
-			   group_x + item_x, group_y + item_y);
-
 #ifdef USE_PIXMAP
 		  item = goo_canvas_image_new (group, NULL, item_x, item_y,
 					       "pattern", pattern,
@@ -179,15 +170,20 @@ setup_canvas (GtkWidget *canvas)
 					      item_width, item_height,
 					      NULL);
 #ifdef SET_STYLE
-		  goo_canvas_item_set_style (item, (j % 2) ? style : style2);
+		  goo_canvas_item_simple_set_style ((GooCanvasItemSimple*) item, (j % 2) ? style : style2);
 #endif
 #ifdef ROTATE
-		  goo_canvas_item_rotate (item, rotation, rotation_x, rotation_y);
+		  cairo_matrix_init_identity (&item_matrix);
+		  cairo_matrix_translate (&item_matrix, rotation_x, rotation_y);
+		  cairo_matrix_rotate (&item_matrix, rotation);
+		  cairo_matrix_translate (&item_matrix, -rotation_x, -rotation_y);
+		  goo_canvas_item_set_transform (item, &item_matrix);
 #endif
 #endif
-		  g_object_set_data (G_OBJECT (item), "id",
-				     ids[id_item_num]);
-
+#if 1
+		  g_object_set_qdata (G_OBJECT (item), id_quark,
+				      ids[id_item_num]);
+#endif
 #if 0
 		  g_signal_connect (item, "motion_notify_event",
 				    G_CALLBACK (on_motion_notify), NULL);
@@ -197,8 +193,14 @@ setup_canvas (GtkWidget *canvas)
 		  item = goo_canvas_text_new (group, ids[id_item_num],
 					      item_x + item_width / 2,
 					      item_y + item_height / 2,
-					      -1, GTK_ANCHOR_CENTER,
+					      item_width, GTK_ANCHOR_CENTER,
+					      /*"font-desc", font_desc,*/
+					      /*"height", item_height,*/
+					      /*"alignment", PANGO_ALIGN_CENTER,*/
 					      NULL);
+		  /* FIXME: This is slightly naughty, but much faster. */
+		  GOO_CANVAS_TEXT (item)->height = item_height;
+		  GOO_CANVAS_TEXT (item)->alignment = PANGO_ALIGN_CENTER;
 #else
 		  item = goo_canvas_rect_new (group, item_x + 20, item_y + 4,
 					      item_width - 40, item_height - 8,
@@ -206,8 +208,7 @@ setup_canvas (GtkWidget *canvas)
 #endif
 
 #ifdef ROTATE
-		  goo_canvas_item_rotate (item, rotation, rotation_x,
-					  rotation_y);
+		  goo_canvas_item_set_transform (item, &item_matrix);
 #endif
 		  id_item_num++;
 		  total_items += 2;
@@ -259,6 +260,32 @@ create_canvas (void)
 {
   GtkWidget *canvas;
 
+#ifdef USE_PIXMAP
+  pixbuf = gdk_pixbuf_new_from_file("toroid.png", NULL);
+  item_width = gdk_pixbuf_get_width (pixbuf);
+  item_height = gdk_pixbuf_get_height (pixbuf);
+  pattern = goo_canvas_cairo_pattern_from_pixbuf (pixbuf);
+#else
+  pixbuf = NULL;
+  item_width = ITEM_WIDTH;
+  item_height = 19;
+#endif
+
+  cell_width = item_width + PADDING * 2;
+  cell_height = item_height + PADDING * 2;
+
+  group_width = N_COLS * cell_width;
+  group_height = N_ROWS * cell_height;
+
+  total_width = N_GROUP_COLS * group_width;
+  total_height = N_GROUP_ROWS * group_height;
+
+  /* We use -ve offsets to test if -ve coords are handled correctly. */
+  left_offset = -total_width / 2;
+  top_offset = -total_height / 2;
+
+  init_ids ();
+
   /* Create the canvas. */
   canvas = goo_canvas_new ();
   gtk_widget_set_size_request (canvas, 600, 450);
diff --git a/src/goocanvasgrid.c b/src/goocanvasgrid.c
index 9ecc7f4..54b9542 100644
--- a/src/goocanvasgrid.c
+++ b/src/goocanvasgrid.c
@@ -452,7 +452,7 @@ paint_vertical_lines (GooCanvasItemSimple   *simple,
   max_x = grid->x + grid->width;
   max_y = grid->y + grid->height;
 
-  has_stroke = goo_canvas_style_set_stroke_options (simple->style, cr);
+  has_stroke = goo_canvas_item_simple_set_stroke_options (simple, cr);
   line_width = goo_canvas_item_simple_get_line_width (simple);
 
   /* If the grid's vertical grid line pattern/color has been set, use that.
@@ -512,7 +512,7 @@ paint_horizontal_lines (GooCanvasItemSimple   *simple,
   max_x = grid->x + grid->width;
   max_y = grid->y + grid->height;
 
-  has_stroke = goo_canvas_style_set_stroke_options (simple->style, cr);
+  has_stroke = goo_canvas_item_simple_set_stroke_options (simple, cr);
   line_width = goo_canvas_item_simple_get_line_width (simple);
 
   /* If the grid's horizontal grid line pattern/color has been set, use that.
@@ -567,7 +567,7 @@ goo_canvas_grid_paint (GooCanvasItemSimple   *simple,
   gdouble half_border_width;
 
   /* Paint the background in the fill pattern/color, if one is set. */
-  if (goo_canvas_style_set_fill_options (simple->style, cr))
+  if (goo_canvas_item_simple_set_fill_options (simple, cr))
     {
       cairo_rectangle (cr, grid->x, grid->y,
 		       grid->width, grid->height);
@@ -605,7 +605,7 @@ goo_canvas_grid_paint (GooCanvasItemSimple   *simple,
       if (grid->border_pattern)
 	cairo_set_source (cr, grid->border_pattern);
       else
-	goo_canvas_style_set_stroke_options (simple->style, cr);
+	goo_canvas_item_simple_set_stroke_options (simple, cr);
 
       cairo_set_line_width (cr, grid->border_width);
       half_border_width = grid->border_width / 2.0;
diff --git a/src/goocanvasgroup.c b/src/goocanvasgroup.c
index 66a47fe..87f19de 100644
--- a/src/goocanvasgroup.c
+++ b/src/goocanvasgroup.c
@@ -404,8 +404,6 @@ goo_canvas_group_update  (GooCanvasItem   *item,
       simple->need_update = FALSE;
       simple->need_entire_subtree_update = FALSE;
 
-      goo_canvas_item_simple_check_style (simple);
-
       simple->bounds.x1 = simple->bounds.y1 = 0.0;
       simple->bounds.x2 = simple->bounds.y2 = 0.0;
 
diff --git a/src/goocanvasimage.c b/src/goocanvasimage.c
index 4164c20..8ef7a33 100644
--- a/src/goocanvasimage.c
+++ b/src/goocanvasimage.c
@@ -279,7 +279,7 @@ goo_canvas_image_paint (GooCanvasItemSimple   *simple,
   cairo_matrix_translate (&matrix, -image->x, -image->y);
 
   cairo_pattern_set_matrix (image->pattern, &matrix);
-  goo_canvas_style_set_fill_options (simple->style, cr);
+  goo_canvas_item_simple_set_fill_options (simple, cr);
   cairo_set_source (cr, image->pattern);
   cairo_rectangle (cr, image->x, image->y,
 		   image->width, image->height);
diff --git a/src/goocanvasitem.c b/src/goocanvasitem.c
index 805f11d..2599965 100644
--- a/src/goocanvasitem.c
+++ b/src/goocanvasitem.c
@@ -56,8 +56,6 @@ enum {
 
 static guint canvas_item_signals[LAST_SIGNAL] = { 0 };
 
-extern void _goo_canvas_style_init (void);
-
 
 G_DEFINE_TYPE (GooCanvasItem, goo_canvas_item, G_TYPE_OBJECT)
 
@@ -429,8 +427,6 @@ goo_canvas_item_class_init (GooCanvasItemClass *klass)
 		  G_TYPE_BOOLEAN, 2,
 		  GOO_TYPE_CANVAS_ITEM,
 		  GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
-
-  _goo_canvas_style_init ();
 }
 
 
@@ -1108,42 +1104,6 @@ goo_canvas_item_skew_y         (GooCanvasItem *item,
 }
 
 
-/**
- * goo_canvas_item_get_style:
- * @item: an item.
- * 
- * Gets the item's style. If the item doesn't have its own style it will return
- * its parent's style.
- * 
- * Returns: the item's style.
- **/
-GooCanvasStyle*
-goo_canvas_item_get_style      (GooCanvasItem   *item)
-{
-  GooCanvasItemClass *item_class = GOO_CANVAS_ITEM_GET_CLASS (item);
-
-  return item_class->get_style ? item_class->get_style (item) : NULL;
-}
-
-
-/**
- * goo_canvas_item_set_style:
- * @item: an item.
- * @style: a style.
- * 
- * Sets the item's style, by copying the properties from the given style.
- **/
-void
-goo_canvas_item_set_style      (GooCanvasItem   *item,
-				GooCanvasStyle  *style)
-{
-  GooCanvasItemClass *item_class = GOO_CANVAS_ITEM_GET_CLASS (item);
-
-  if (item_class->set_style)
-    item_class->set_style (item, style);
-}
-
-
 typedef struct _GooCanvasItemAnimation  GooCanvasItemAnimation;
 struct _GooCanvasItemAnimation
 {
diff --git a/src/goocanvasitem.h b/src/goocanvasitem.h
index 25cabdd..de8ee8f 100644
--- a/src/goocanvasitem.h
+++ b/src/goocanvasitem.h
@@ -8,7 +8,6 @@
 #define __GOO_CANVAS_ITEM_H__
 
 #include <gtk/gtk.h>
-#include "goocanvasstyle.h"
 
 G_BEGIN_DECLS
 
@@ -141,8 +140,7 @@ struct _GooCanvasItem
  * inside a layout container like #GooCanvasTable).
  *
  * Items that support transforms should also implement get_transform() and
- * set_transform(). Items that support styles should implement get_style()
- * and set_style().
+ * set_transform().
  *
  * Container items must implement get_canvas(), set_canvas(),
  * get_n_children(), get_child() and request_update(). Containers that support
@@ -226,9 +224,6 @@ struct _GooCanvasItemClass
 							 cairo_matrix_t		*transform);
   void			(* set_transform)		(GooCanvasItem		*item,
 							 const cairo_matrix_t	*transform);
-  GooCanvasStyle*	(* get_style)			(GooCanvasItem		*item);
-  void			(* set_style)			(GooCanvasItem		*item,
-							 GooCanvasStyle		*style);
   gboolean		(* is_visible)			(GooCanvasItem		*item);
   gboolean		(* get_can_focus)		(GooCanvasItem		*item);
   gdouble               (* get_requested_height)	(GooCanvasItem		*item,
@@ -393,10 +388,6 @@ void               goo_canvas_item_skew_y         (GooCanvasItem   *item,
 						   gdouble          cx,
 						   gdouble          cy);
 
-GooCanvasStyle*    goo_canvas_item_get_style      (GooCanvasItem   *item);
-void               goo_canvas_item_set_style      (GooCanvasItem   *item,
-						   GooCanvasStyle  *style);
-
 void               goo_canvas_item_animate        (GooCanvasItem   *item,
 						   gdouble           x,
 						   gdouble           y,
diff --git a/src/goocanvasitemsimple.c b/src/goocanvasitemsimple.c
index 8e48ead..0be1c6f 100644
--- a/src/goocanvasitemsimple.c
+++ b/src/goocanvasitemsimple.c
@@ -135,9 +135,8 @@ goo_canvas_item_simple_get_property (GObject              *object,
 				     GParamSpec           *pspec)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
-  AtkObject *accessible;
   GooCanvasStyle *style = simple->style;
-  GValue *svalue;
+  AtkObject *accessible;
   gdouble line_width = 2.0;
   gchar *font = NULL;
 
@@ -157,81 +156,62 @@ goo_canvas_item_simple_get_property (GObject              *object,
 
       /* Basic drawing properties. */
     case PROP_STROKE_PATTERN:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_stroke_pattern_id);
-      g_value_set_boxed (value, svalue ? svalue->data[0].v_pointer : NULL);
+      g_value_set_boxed (value, style ? style->stroke_pattern : NULL);
       break;
     case PROP_FILL_PATTERN:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_fill_pattern_id);
-      g_value_set_boxed (value, svalue ? svalue->data[0].v_pointer : NULL);
+      g_value_set_boxed (value, style ? style->fill_pattern : NULL);
       break;
     case PROP_FILL_RULE:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_fill_rule_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_FILL_RULE_WINDING);
+      g_value_set_enum (value, style ? style->fill_rule : CAIRO_FILL_RULE_WINDING);
       break;
     case PROP_OPERATOR:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_operator_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_OPERATOR_OVER);
+      g_value_set_enum (value, style ? style->op : CAIRO_OPERATOR_OVER);
       break;
     case PROP_ANTIALIAS:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_antialias_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_ANTIALIAS_GRAY);
+      g_value_set_enum (value, style ? style->antialias : CAIRO_ANTIALIAS_GRAY);
       break;
 
       /* Line style & width properties. */
     case PROP_LINE_WIDTH:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_line_width_id);
-      if (svalue)
-	line_width = svalue->data[0].v_double;
+      if (style)
+	line_width = style->line_width;
       else if (simple->canvas)
 	line_width = goo_canvas_get_default_line_width (simple->canvas);
       g_value_set_double (value, line_width);
       break;
     case PROP_LINE_CAP:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_line_cap_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_LINE_CAP_BUTT);
+      g_value_set_enum (value, style ? style->line_cap : CAIRO_LINE_CAP_BUTT);
       break;
     case PROP_LINE_JOIN:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_line_join_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_LINE_JOIN_MITER);
+      g_value_set_enum (value, style ? style->line_join : CAIRO_LINE_JOIN_MITER);
       break;
     case PROP_LINE_JOIN_MITER_LIMIT:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_line_join_miter_limit_id);
-      g_value_set_double (value, svalue ? svalue->data[0].v_double : 10.0);
+      g_value_set_double (value, style ? style->line_join_miter_limit : 10.0);
       break;
     case PROP_LINE_DASH:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_line_dash_id);
-      g_value_set_boxed (value, svalue ? svalue->data[0].v_pointer : NULL);
+      g_value_set_boxed (value, style ? style->dash : NULL);
       break;
 
       /* Font properties. */
     case PROP_FONT:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_font_desc_id);
-      if (svalue)
-	font = pango_font_description_to_string (svalue->data[0].v_pointer);
+      if (style->font_desc)
+	font = pango_font_description_to_string (style->font_desc);
       g_value_set_string (value, font);
       g_free (font);
       break;
     case PROP_FONT_DESC:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_font_desc_id);
-      g_value_set_boxed (value, svalue ? svalue->data[0].v_pointer : NULL);
+      g_value_set_boxed (value, style ? style->font_desc : NULL);
       break;
     case PROP_HINT_METRICS:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_hint_metrics_id);
-      g_value_set_enum (value, svalue ? svalue->data[0].v_long : CAIRO_HINT_METRICS_OFF);
+      g_value_set_enum (value, style->hint_metrics);
       break;
 
       /* Convenience properties. */
     case PROP_STROKE_COLOR_RGBA:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_stroke_pattern_id);
-      if (svalue)
-	goo_canvas_get_rgba_value_from_pattern (svalue->data[0].v_pointer,
-						value);
+      goo_canvas_get_rgba_value_from_pattern (style ? style->stroke_pattern : NULL, value);
       break;
     case PROP_FILL_COLOR_RGBA:
-      svalue = goo_canvas_style_get_property (style, goo_canvas_style_fill_pattern_id);
-      if (svalue)
-	goo_canvas_get_rgba_value_from_pattern (svalue->data[0].v_pointer,
-						value);
+      goo_canvas_get_rgba_value_from_pattern (style ? style->fill_pattern : NULL, value);
       break;
 
       /* Other properties. */
@@ -271,29 +251,20 @@ goo_canvas_item_simple_set_property (GObject              *object,
 {
   GooCanvasItem *item = (GooCanvasItem*) object;
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+  GooCanvasStyle *style;
   GooCanvasItem *parent;
   AtkObject *accessible;
-  GooCanvasStyle *style;
   cairo_pattern_t *pattern;
   gboolean need_update = TRUE, recompute_bounds = FALSE;
   cairo_matrix_t *transform;
-  GValue tmpval = { 0 };
   const char *font_name;
   PangoFontDescription *font_desc = NULL;
 
-  /* See if we need to create our own style. */
+  /* See if we need to create a style. */
   if (prop_id < PROP_TRANSFORM)
     {
       if (!simple->style)
-	{
-	  simple->style = goo_canvas_style_new ();
-	}
-      else if (!simple->own_style)
-	{
-	  g_object_unref (simple->style);
-	  simple->style = goo_canvas_style_new ();
-	}
-      simple->own_style = TRUE;
+	simple->style = goo_canvas_style_new ();
     }
 
   style = simple->style;
@@ -319,89 +290,102 @@ goo_canvas_item_simple_set_property (GObject              *object,
 
       /* Basic drawing properties. */
     case PROP_STROKE_PATTERN:
-      goo_canvas_style_set_property (style, goo_canvas_style_stroke_pattern_id, value);
+      goo_canvas_style_set_stroke_pattern (style, g_value_get_boxed (value));
       break;
     case PROP_FILL_PATTERN:
-      goo_canvas_style_set_property (style, goo_canvas_style_fill_pattern_id, value);
+      goo_canvas_style_set_fill_pattern (style, g_value_get_boxed (value));
       break;
     case PROP_FILL_RULE:
-      goo_canvas_style_set_property (style, goo_canvas_style_fill_rule_id, value);
+      style->fill_rule = g_value_get_enum (value);
       break;
     case PROP_OPERATOR:
-      goo_canvas_style_set_property (style, goo_canvas_style_operator_id, value);
+      style->op = g_value_get_enum (value);
       break;
     case PROP_ANTIALIAS:
-      goo_canvas_style_set_property (style, goo_canvas_style_antialias_id, value);
+      style->antialias = g_value_get_enum (value);
       break;
 
       /* Line style & width properties. */
     case PROP_LINE_WIDTH:
-      goo_canvas_style_set_property (style, goo_canvas_style_line_width_id, value);
+      style->line_width = g_value_get_double (value);
       recompute_bounds = TRUE;
       break;
     case PROP_LINE_CAP:
-      goo_canvas_style_set_property (style, goo_canvas_style_line_cap_id, value);
+      style->line_cap = g_value_get_enum (value);
       recompute_bounds = TRUE;
       break;
     case PROP_LINE_JOIN:
-      goo_canvas_style_set_property (style, goo_canvas_style_line_join_id, value);
+      style->line_join = g_value_get_enum (value);
       recompute_bounds = TRUE;
       break;
     case PROP_LINE_JOIN_MITER_LIMIT:
-      goo_canvas_style_set_property (style, goo_canvas_style_line_join_miter_limit_id,
-				     value);
+      style->line_join_miter_limit = g_value_get_double (value);
       recompute_bounds = TRUE;
       break;
     case PROP_LINE_DASH:
-      goo_canvas_style_set_property (style, goo_canvas_style_line_dash_id, value);
+      goo_canvas_line_dash_unref (style->dash);
+      style->dash = g_value_get_boxed (value);
+      goo_canvas_line_dash_ref (style->dash);
       recompute_bounds = TRUE;
       break;
 
       /* Font properties. */
     case PROP_FONT:
+      if (style->font_desc)
+	pango_font_description_free (style->font_desc);
       font_name = g_value_get_string (value);
       if (font_name)
-	font_desc = pango_font_description_from_string (font_name);
-      g_value_init (&tmpval, PANGO_TYPE_FONT_DESCRIPTION);
-      g_value_take_boxed (&tmpval, font_desc);
-      goo_canvas_style_set_property (style, goo_canvas_style_font_desc_id, &tmpval);
-      g_value_unset (&tmpval);
+	style->font_desc = pango_font_description_from_string (font_name);
+      else
+	style->font_desc = NULL;
       recompute_bounds = TRUE;
       break;
     case PROP_FONT_DESC:
-      goo_canvas_style_set_property (style, goo_canvas_style_font_desc_id, value);
+      if (style->font_desc)
+	pango_font_description_free (style->font_desc);
+      font_desc = g_value_get_boxed (value);
+      if (font_desc)
+	style->font_desc = pango_font_description_copy (font_desc);
+      else
+	style->font_desc = NULL;
       recompute_bounds = TRUE;
       break;
     case PROP_HINT_METRICS:
-      goo_canvas_style_set_property (style, goo_canvas_style_hint_metrics_id, value);
+      style->hint_metrics = g_value_get_enum (value);
       recompute_bounds = TRUE;
       break;
 
       /* Convenience properties. */
     case PROP_STROKE_COLOR:
       pattern = goo_canvas_create_pattern_from_color_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
     case PROP_STROKE_COLOR_RGBA:
       pattern = goo_canvas_create_pattern_from_rgba_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
     case PROP_STROKE_PIXBUF:
       pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_stroke_pattern_id, pattern);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
 
     case PROP_FILL_COLOR:
       pattern = goo_canvas_create_pattern_from_color_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
     case PROP_FILL_COLOR_RGBA:
       pattern = goo_canvas_create_pattern_from_rgba_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
     case PROP_FILL_PIXBUF:
       pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
-      goo_canvas_set_style_property_from_pattern (style, goo_canvas_style_fill_pattern_id, pattern);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
       break;
 
       /* Other properties. */
@@ -558,39 +542,6 @@ goo_canvas_item_simple_set_transform (GooCanvasItem        *item,
 }
 
 
-static GooCanvasStyle*
-goo_canvas_item_simple_get_style (GooCanvasItem       *item)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-
-  return simple->style;
-}
-
-
-static void
-goo_canvas_item_simple_set_style (GooCanvasItem  *item,
-				  GooCanvasStyle *style)
-{
-  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-
-  if (simple->style)
-    g_object_unref (simple->style);
-
-  if (style)
-    {
-      simple->style = goo_canvas_style_copy (style);
-      simple->own_style = TRUE;
-    }
-  else
-    {
-      simple->style = NULL;
-      simple->own_style = FALSE;
-    }
-
-  goo_canvas_item_simple_changed (simple, TRUE);
-}
-
-
 static void
 goo_canvas_item_simple_get_bounds  (GooCanvasItem   *item,
 				    GooCanvasBounds *bounds)
@@ -743,44 +694,6 @@ goo_canvas_item_simple_set_is_static  (GooCanvasItem   *item,
 }
 
 
-/**
- * goo_canvas_item_simple_check_style:
- * @item: a #GooCanvasItemSimple.
- * 
- * This function is intended to be used by subclasses of #GooCanvasItemSimple,
- * typically in their update() or get_requested_area() methods.
- *
- * It ensures that the item's style is setup correctly. If the item has its
- * own #GooCanvasStyle it makes sure the parent is set correctly. If it
- * doesn't have its own style it uses the parent item's style.
- **/
-void
-goo_canvas_item_simple_check_style (GooCanvasItemSimple *simple)
-{
-  GooCanvasStyle *parent_style = NULL;
-
-  if (simple->parent)
-    parent_style = goo_canvas_item_get_style (simple->parent);
-
-  if (simple->own_style)
-    {
-      goo_canvas_style_set_parent (simple->style, parent_style);
-    }
-  else if (simple->style != parent_style)
-    {
-      /* The item doesn't have its own style so we use the parent's (though
-	 that may also be NULL). */
-      if (simple->style)
-	g_object_unref (simple->style);
-
-      simple->style = parent_style;
-
-      if (parent_style)
-	g_object_ref (parent_style);
-    }
-}
-
-
 static void
 goo_canvas_item_simple_update_internal  (GooCanvasItemSimple *simple,
 					 cairo_t             *cr)
@@ -791,8 +704,6 @@ goo_canvas_item_simple_update_internal  (GooCanvasItemSimple *simple,
 
   simple->need_update = FALSE;
 
-  goo_canvas_item_simple_check_style (simple);
-
   cairo_get_matrix (cr, &transform);
 
   class->simple_update (simple, cr);
@@ -1064,12 +975,10 @@ void
 goo_canvas_item_simple_paint_path (GooCanvasItemSimple *simple,
 				   cairo_t             *cr)
 {
-  GooCanvasStyle *style = simple->style;
-
-  if (goo_canvas_style_set_fill_options (style, cr))
+  if (goo_canvas_item_simple_set_fill_options (simple, cr))
     cairo_fill_preserve (cr);
 
-  if (goo_canvas_style_set_stroke_options (style, cr))
+  if (goo_canvas_item_simple_set_stroke_options (simple, cr))
     cairo_stroke (cr);
 
   cairo_new_path (cr);
@@ -1102,16 +1011,15 @@ goo_canvas_item_simple_get_path_bounds (GooCanvasItemSimple *simple,
 					cairo_t             *cr,
 					GooCanvasBounds     *bounds)
 {
-  GooCanvasStyle *style = simple->style;
   GooCanvasBounds fill_bounds, stroke_bounds;
 
   /* Calculate the filled extents. */
-  goo_canvas_style_set_fill_options (style, cr);
+  goo_canvas_item_simple_set_fill_options (simple, cr);
   cairo_fill_extents (cr, &fill_bounds.x1, &fill_bounds.y1,
 		      &fill_bounds.x2, &fill_bounds.y2);
 
   /* Check the stroke. */
-  goo_canvas_style_set_stroke_options (style, cr);
+  goo_canvas_item_simple_set_stroke_options (simple, cr);
   cairo_stroke_extents (cr, &stroke_bounds.x1, &stroke_bounds.y1,
 			&stroke_bounds.x2, &stroke_bounds.y2);
 
@@ -1293,13 +1201,12 @@ goo_canvas_item_simple_check_in_path (GooCanvasItemSimple   *simple,
 				      cairo_t               *cr,
 				      GooCanvasPointerEvents pointer_events)
 {
-  GooCanvasStyle *style = simple->style;
   gboolean do_fill, do_stroke;
 
   /* Check the filled path, if required. */
   if (pointer_events & GOO_CANVAS_EVENTS_FILL_MASK)
     {
-      do_fill = goo_canvas_style_set_fill_options (style, cr);
+      do_fill = goo_canvas_item_simple_set_fill_options (simple, cr);
       if (!(pointer_events & GOO_CANVAS_EVENTS_PAINTED_MASK) || do_fill)
 	{
 	  if (cairo_in_fill (cr, x, y))
@@ -1310,7 +1217,7 @@ goo_canvas_item_simple_check_in_path (GooCanvasItemSimple   *simple,
   /* Check the stroke, if required. */
   if (pointer_events & GOO_CANVAS_EVENTS_STROKE_MASK)
     {
-      do_stroke = goo_canvas_style_set_stroke_options (style, cr);
+      do_stroke = goo_canvas_item_simple_set_stroke_options (simple, cr);
       if (!(pointer_events & GOO_CANVAS_EVENTS_PAINTED_MASK) || do_stroke)
 	{
 	  if (cairo_in_stroke (cr, x, y))
@@ -1333,12 +1240,8 @@ goo_canvas_item_simple_check_in_path (GooCanvasItemSimple   *simple,
 gdouble
 goo_canvas_item_simple_get_line_width (GooCanvasItemSimple   *simple)
 {
-  GValue *value;
-
-  value = goo_canvas_style_get_property (simple->style,
-					 goo_canvas_style_line_width_id);
-  if (value)
-    return value->data[0].v_double;
+  if (simple->style && simple->style->line_width >= 0)
+    return simple->style->line_width;
   else if (simple->canvas)
     return goo_canvas_get_default_line_width (simple->canvas);
   else
@@ -1346,6 +1249,97 @@ goo_canvas_item_simple_get_line_width (GooCanvasItemSimple   *simple)
 }
 
 
+void
+goo_canvas_item_simple_set_style (GooCanvasItemSimple   *simple,
+				  GooCanvasStyle        *style)
+{
+  if (simple->style)
+    g_object_unref (simple->style);
+
+  simple->style = style;
+  if (style)
+    g_object_ref (style);
+
+  goo_canvas_item_simple_changed (simple, TRUE);
+}
+
+
+gboolean
+goo_canvas_item_simple_set_stroke_options (GooCanvasItemSimple   *simple,
+					   cairo_t               *cr)
+{
+  GooCanvasStyle *style = simple->style;
+
+  /* If no style is set, just reset the source to black and return TRUE so the
+     default style will be used. */
+  if (!style)
+    {
+      cairo_set_source_rgb (cr, 0, 0, 0);
+      return TRUE;
+    }
+
+  if (style->stroke_pattern)
+    cairo_set_source (cr, style->stroke_pattern);
+  else
+    cairo_set_source_rgb (cr, 0, 0, 0);
+
+  if (style->op != CAIRO_OPERATOR_OVER)
+    cairo_set_operator (cr, style->op);
+
+  if (style->antialias != CAIRO_ANTIALIAS_GRAY)
+    cairo_set_antialias (cr, style->antialias);
+
+  if (style->line_width >= 0.0)
+    cairo_set_line_width (cr, style->line_width);
+
+  if (style->line_cap != CAIRO_LINE_CAP_BUTT)
+    cairo_set_line_cap (cr, style->line_cap);
+
+  if (style->line_join != CAIRO_LINE_JOIN_MITER)
+    cairo_set_line_join (cr, style->line_join);
+
+  if (style->line_join_miter_limit != 10.0)
+    cairo_set_miter_limit (cr, style->line_join_miter_limit);
+
+  if (style->dash)
+    cairo_set_dash (cr, style->dash->dashes, style->dash->num_dashes,
+		    style->dash->dash_offset);
+
+  /* If the style pattern has been explicitly set to NULL return FALSE, as no
+     stroke is wanted. */
+  if (style->stroke_pattern_set && !style->stroke_pattern)
+    return FALSE;
+
+  return TRUE;
+}
+
+
+gboolean
+goo_canvas_item_simple_set_fill_options (GooCanvasItemSimple   *simple,
+					 cairo_t               *cr)
+{
+  GooCanvasStyle *style = simple->style;
+
+  /* If no style is set, just return FALSE as no fill is needed. */
+  if (!style)
+    return FALSE;
+
+  if (style->fill_pattern)
+    cairo_set_source (cr, style->fill_pattern);
+
+  if (style->op != CAIRO_OPERATOR_OVER)
+    cairo_set_operator (cr, style->op);
+
+  if (style->antialias != CAIRO_ANTIALIAS_GRAY)
+    cairo_set_antialias (cr, style->antialias);
+
+  if (style->fill_rule != CAIRO_FILL_RULE_WINDING)
+    cairo_set_fill_rule (cr, style->fill_rule);
+
+  return style->fill_pattern ? TRUE : FALSE;
+}
+
+
 static void
 goo_canvas_item_simple_class_init (GooCanvasItemSimpleClass *klass)
 {
@@ -1371,8 +1365,6 @@ goo_canvas_item_simple_class_init (GooCanvasItemSimpleClass *klass)
 
   item_class->get_transform      = goo_canvas_item_simple_get_transform;
   item_class->set_transform      = goo_canvas_item_simple_set_transform;
-  item_class->get_style          = goo_canvas_item_simple_get_style;
-  item_class->set_style          = goo_canvas_item_simple_set_style;
   item_class->is_visible         = goo_canvas_item_simple_is_visible;
   item_class->get_can_focus	 = goo_canvas_item_simple_get_can_focus;
   item_class->get_is_static	 = goo_canvas_item_simple_get_is_static;
diff --git a/src/goocanvasitemsimple.h b/src/goocanvasitemsimple.h
index 21f351f..52fc324 100644
--- a/src/goocanvasitemsimple.h
+++ b/src/goocanvasitemsimple.h
@@ -34,7 +34,8 @@ typedef struct _GooCanvasItemSimpleClass  GooCanvasItemSimpleClass;
  * @bounds: the bounds of the item, in device space.
  * @need_update: if the item needs to recompute its bounds and redraw.
  * @need_entire_subtree_update: if all descendants need to be updated.
- * @style: the style to draw with.
+ * @pen: the pen to draw the strokes with.
+ * @brush: the brush to fill the items with.
  * @transform: the transformation matrix of the item, or %NULL.
  * @clip_path_commands: an array of #GooCanvasPathCommand specifying the clip
  *  path of the item, or %NULL.
@@ -46,7 +47,6 @@ typedef struct _GooCanvasItemSimpleClass  GooCanvasItemSimpleClass;
  * @pointer_events: the #GooCanvasPointerEvents setting specifying the events
  *  the item should receive.
  * @can_focus: if the item can take the keyboard focus.
- * @own_style: if the item has its own style, rather than using its parent's.
  * @clip_fill_rule: the #cairo_fill_rule_t setting specifying the fill rule
  *  used for the clip path.
  * @is_static: if the item is static.
@@ -76,7 +76,6 @@ struct _GooCanvasItemSimple
   guint visibility			: 2;
   guint pointer_events			: 4;
   guint can_focus                       : 1;
-  guint own_style                       : 1;
   guint clip_fill_rule			: 4;
   guint is_static			: 1;
 };
@@ -133,6 +132,8 @@ struct _GooCanvasItemSimpleClass
 
 GType    goo_canvas_item_simple_get_type		(void) G_GNUC_CONST;
 
+void     goo_canvas_item_simple_set_style		(GooCanvasItemSimple   *simple,
+							 GooCanvasStyle        *style);
 
 void     goo_canvas_item_simple_get_path_bounds		(GooCanvasItemSimple	*item,
 							 cairo_t		*cr,
@@ -153,9 +154,12 @@ void     goo_canvas_item_simple_paint_path		(GooCanvasItemSimple	*item,
 
 void     goo_canvas_item_simple_changed			(GooCanvasItemSimple	*item,
 							 gboolean		 recompute_bounds);
-void     goo_canvas_item_simple_check_style		(GooCanvasItemSimple	*item);
 gdouble  goo_canvas_item_simple_get_line_width		(GooCanvasItemSimple   *item);
 
+gboolean goo_canvas_item_simple_set_stroke_options	(GooCanvasItemSimple   *simple,
+							 cairo_t               *cr);
+gboolean goo_canvas_item_simple_set_fill_options	(GooCanvasItemSimple   *simple,
+							 cairo_t               *cr);
 
 
 G_END_DECLS
diff --git a/src/goocanvaspath.c b/src/goocanvaspath.c
index 801360c..ff1a5d5 100644
--- a/src/goocanvaspath.c
+++ b/src/goocanvaspath.c
@@ -447,7 +447,7 @@ goo_canvas_path_is_item_at (GooCanvasItemSimple *simple,
   gboolean do_fill;
 
   /* By default only check the fill if a fill color/pattern is specified. */
-  do_fill = goo_canvas_style_set_fill_options (simple->style, cr);
+  do_fill = goo_canvas_item_simple_set_fill_options (simple, cr);
   if (!do_fill)
     pointer_events &= ~GOO_CANVAS_EVENTS_FILL_MASK;
 
diff --git a/src/goocanvaspolyline.c b/src/goocanvaspolyline.c
index bd0dd11..08ba072 100644
--- a/src/goocanvaspolyline.c
+++ b/src/goocanvaspolyline.c
@@ -777,7 +777,7 @@ goo_canvas_polyline_is_item_at (GooCanvasItemSimple *simple,
       && (pointer_events & GOO_CANVAS_EVENTS_STROKE_MASK))
     {
       /* We use the stroke pattern to match the style of the line. */
-      do_stroke = goo_canvas_style_set_stroke_options (simple->style, cr);
+      do_stroke = goo_canvas_item_simple_set_stroke_options (simple, cr);
       if (!(pointer_events & GOO_CANVAS_EVENTS_PAINTED_MASK) || do_stroke)
 	{
 	  if (polyline->start_arrow)
@@ -827,7 +827,7 @@ goo_canvas_polyline_compute_bounds (GooCanvasPolyline     *polyline,
       && polyline->num_points >= 2)
     {
       /* We use the stroke pattern to match the style of the line. */
-      goo_canvas_style_set_stroke_options (simple->style, cr);
+      goo_canvas_item_simple_set_stroke_options (simple, cr);
 
       if (polyline->start_arrow)
 	{
@@ -887,7 +887,7 @@ goo_canvas_polyline_paint (GooCanvasItemSimple   *simple,
       && polyline->num_points >= 2)
     {
       /* We use the stroke pattern to match the style of the line. */
-      goo_canvas_style_set_stroke_options (simple->style, cr);
+      goo_canvas_item_simple_set_stroke_options (simple, cr);
 
       if (polyline->start_arrow)
 	{
diff --git a/src/goocanvasstyle.c b/src/goocanvasstyle.c
index 6ca878d..4d6f01e 100644
--- a/src/goocanvasstyle.c
+++ b/src/goocanvasstyle.c
@@ -1,542 +1,465 @@
 /*
- * GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
+ * GooCanvas. Copyright (C) 2005-2010 Damon Chaplin.
  * Released under the GNU LGPL license. See COPYING for details.
  *
- * goocanvasstyle.c - cascading styles.
- */
-
-/**
- * SECTION:goocanvasstyle
- * @Title: GooCanvasStyle
- * @Short_Description: support for cascading style properties for canvas items.
- *
- * #GooCanvasStyle provides support for cascading style properties for canvas
- * items. It is intended to be used when implementing new canvas items.
- *
- * Style properties are identified by a unique #GQuark, and contain
- * arbitrary data stored in a #GValue.
- *
- * #GooCanvasStyle also provides a few convenience functions such as
- * goo_canvas_style_set_stroke_options() and
- * goo_canvas_style_set_fill_options() which efficiently apply an item's
- * standard style properties to the given cairo_t.
+ * goocanvasstyle.c - 
  */
 #include <config.h>
+#include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
 #include "goocanvasstyle.h"
-#include "goocanvasutils.h"
-
-/* GQuarks for the basic properties. */
-
-/**
- * goo_canvas_style_stroke_pattern_id:
- * 
- * Unique #GQuark identifier used for the standard stroke pattern property.
- **/
-GQuark goo_canvas_style_stroke_pattern_id;
-
-/**
- * goo_canvas_style_fill_pattern_id:
- * 
- * Unique #GQuark identifier used for the standard fill pattern property.
- **/
-GQuark goo_canvas_style_fill_pattern_id;
-
-/**
- * goo_canvas_style_fill_rule_id:
- * 
- * Unique #GQuark identifier used for the standard fill rule property.
- **/
-GQuark goo_canvas_style_fill_rule_id;
-
-/**
- * goo_canvas_style_operator_id:
- * 
- * Unique #GQuark identifier used for the standard operator property.
- **/
-GQuark goo_canvas_style_operator_id;
-
-/**
- * goo_canvas_style_antialias_id:
- * 
- * Unique #GQuark identifier used for the standard antialias property.
- **/
-GQuark goo_canvas_style_antialias_id;
-
-/**
- * goo_canvas_style_line_width_id:
- * 
- * Unique #GQuark identifier used for the standard line width property.
- **/
-GQuark goo_canvas_style_line_width_id;
-
-/**
- * goo_canvas_style_line_cap_id:
- * 
- * Unique #GQuark identifier used for the standard line cap property.
- **/
-GQuark goo_canvas_style_line_cap_id;
-
-/**
- * goo_canvas_style_line_join_id:
- * 
- * Unique #GQuark identifier used for the standard line join property.
- **/
-GQuark goo_canvas_style_line_join_id;
-
-/**
- * goo_canvas_style_line_join_miter_limit_id:
- * 
- * Unique #GQuark identifier used for the standard miter limit property.
- **/
-GQuark goo_canvas_style_line_join_miter_limit_id;
-
-/**
- * goo_canvas_style_line_dash_id:
- * 
- * Unique #GQuark identifier used for the standard line dash property.
- **/
-GQuark goo_canvas_style_line_dash_id;
-
-/**
- * goo_canvas_style_font_desc_id:
- * 
- * Unique #GQuark identifier used for the standard font description property.
- **/
-GQuark goo_canvas_style_font_desc_id;
-
-/**
- * goo_canvas_style_hint_metrics_id:
- * 
- * Unique #GQuark identifier used for the standard hint metrics property.
- **/
-GQuark goo_canvas_style_hint_metrics_id;
-
-static void goo_canvas_style_dispose  (GObject *object);
-static void goo_canvas_style_finalize (GObject *object);
+#include "goocanvasprivate.h"
+
 
 G_DEFINE_TYPE (GooCanvasStyle, goo_canvas_style, G_TYPE_OBJECT)
 
 
-/* Create GQuarks for the basic properties. This is called by
-   goo_canvas_style_class_init(), goo_canvas_item_base_init() and
-   goo_canvas_item_model_base_init() to try to ensure the GQuarks are
-   initialized before they are needed. */
-void
-_goo_canvas_style_init (void)
-{
-  static gboolean initialized = FALSE;
-  
-  if (!initialized)
-    {
-      goo_canvas_style_stroke_pattern_id = g_quark_from_static_string ("GooCanvasStyle:stroke_pattern");
-      goo_canvas_style_fill_pattern_id = g_quark_from_static_string ("GooCanvasStyle:fill_pattern");
-      goo_canvas_style_fill_rule_id = g_quark_from_static_string ("GooCanvasStyle:fill_rule");
-      goo_canvas_style_operator_id = g_quark_from_static_string ("GooCanvasStyle:operator");
-      goo_canvas_style_antialias_id = g_quark_from_static_string ("GooCanvasStyle:antialias");
-      goo_canvas_style_line_width_id = g_quark_from_static_string ("GooCanvasStyle:line_width");
-      goo_canvas_style_line_cap_id = g_quark_from_static_string ("GooCanvasStyle:line_cap");
-      goo_canvas_style_line_join_id = g_quark_from_static_string ("GooCanvasStyle:line_join");
-      goo_canvas_style_line_join_miter_limit_id = g_quark_from_static_string ("GooCanvasStyle:line_join_miter_limit");
-      goo_canvas_style_line_dash_id = g_quark_from_static_string ("GooCanvasStyle:line_dash");
-      goo_canvas_style_font_desc_id = g_quark_from_static_string ("GooCanvasStyle:font_desc");
-      goo_canvas_style_hint_metrics_id = g_quark_from_static_string ("GooCanvasStyle:hint_metrics");
-
-      initialized = TRUE;
-    }
-}
+enum {
+  PROP_0,
 
+  /* Basic drawing properties. */
+  PROP_STROKE_PATTERN,
+  PROP_FILL_PATTERN,
+  PROP_FILL_RULE,
+  PROP_OPERATOR,
+  PROP_ANTIALIAS,
 
-static void
-goo_canvas_style_class_init (GooCanvasStyleClass *klass)
-{
-  GObjectClass *gobject_class = (GObjectClass*) klass;
+  /* Line style & width properties. */
+  PROP_LINE_WIDTH,
+  PROP_LINE_CAP,
+  PROP_LINE_JOIN,
+  PROP_LINE_JOIN_MITER_LIMIT,
+  PROP_LINE_DASH,
 
-  gobject_class->dispose  = goo_canvas_style_dispose;
-  gobject_class->finalize = goo_canvas_style_finalize;
+  /* Font properties. */
+  PROP_FONT,
+  PROP_FONT_DESC,
+  PROP_HINT_METRICS,
 
-  _goo_canvas_style_init ();
-}
+  /* Convenience properties. */
+  PROP_STROKE_COLOR,
+  PROP_STROKE_COLOR_RGBA,
+  PROP_STROKE_PIXBUF,
+  PROP_FILL_COLOR,
+  PROP_FILL_COLOR_RGBA,
+  PROP_FILL_PIXBUF
+};
 
 
 static void
 goo_canvas_style_init (GooCanvasStyle *style)
 {
-  style->properties = g_array_new (0, 0, sizeof (GooCanvasStyleProperty));
+  style->stroke_pattern = NULL;
+  style->fill_pattern = NULL;
+
+  style->dash = NULL;
+  style->font_desc = NULL;
+
+  style->line_width = -1.0;
+  style->line_join_miter_limit = 10.0;
+
+  style->stroke_pattern_set = FALSE;
+  style->fill_pattern_set = FALSE;
+  style->op = CAIRO_OPERATOR_OVER;
+  style->antialias = CAIRO_ANTIALIAS_GRAY;
+  style->fill_rule = CAIRO_FILL_RULE_WINDING;
+  style->line_cap = CAIRO_LINE_CAP_BUTT;
+  style->line_join = CAIRO_LINE_JOIN_MITER;
+  style->hint_metrics = CAIRO_HINT_METRICS_OFF;
 }
 
 
-/**
- * goo_canvas_style_new:
- * 
- * Creates a new #GooCanvasStyle.
- * 
- * Returns: a new #GooCanvasStyle.
- **/
 GooCanvasStyle*
 goo_canvas_style_new (void)
 {
-  return GOO_CANVAS_STYLE (g_object_new (GOO_TYPE_CANVAS_STYLE, NULL));
+  return g_object_new (GOO_TYPE_CANVAS_STYLE, NULL);
 }
 
 
 static void
-goo_canvas_style_dispose (GObject *object)
+goo_canvas_style_finalize (GObject *object)
 {
   GooCanvasStyle *style = (GooCanvasStyle*) object;
-  GooCanvasStyleProperty *property;
-  gint i;
 
-  if (style->parent)
+  cairo_pattern_destroy (style->stroke_pattern);
+  cairo_pattern_destroy (style->fill_pattern);
+
+  if (style->dash)
     {
-      g_object_unref (style->parent);
-      style->parent = NULL;
+      goo_canvas_line_dash_unref (style->dash);
+      style->dash = NULL;
     }
 
-  /* Free the property GValues. */
-  for (i = 0; i < style->properties->len; i++)
+  if (style->font_desc)
     {
-      property = &g_array_index (style->properties, GooCanvasStyleProperty, i);
-      g_value_unset (&property->value);
+      pango_font_description_free (style->font_desc);
+      style->font_desc = NULL;
     }
-  g_array_set_size (style->properties, 0);
 
-  G_OBJECT_CLASS (goo_canvas_style_parent_class)->dispose (object);
+  G_OBJECT_CLASS (goo_canvas_style_parent_class)->finalize (object);
 }
 
 
 static void
-goo_canvas_style_finalize (GObject *object)
+goo_canvas_style_get_property (GObject              *object,
+			       guint                 prop_id,
+			       GValue               *value,
+			       GParamSpec           *pspec)
 {
   GooCanvasStyle *style = (GooCanvasStyle*) object;
+  gchar *font = NULL;
 
-  g_array_free (style->properties, TRUE);
-
-  G_OBJECT_CLASS (goo_canvas_style_parent_class)->finalize (object);
-}
-
-
-/**
- * goo_canvas_style_copy:
- * @style: a #GooCanvasStyle.
- * 
- * Copies the given #GooCanvasStyle, by copying all of its properties.
- * Though the parent of the new style is left unset.
- * 
- * Returns: a copy of the given #GooCanvasStyle.
- **/
-GooCanvasStyle*
-goo_canvas_style_copy               (GooCanvasStyle *style)
-{
-  GooCanvasStyle *copy;
-  GooCanvasStyleProperty *property;
-  gint i;
-
-  copy = goo_canvas_style_new ();
-
-  for (i = 0; i < style->properties->len; i++)
+  switch (prop_id)
     {
-      property = &g_array_index (style->properties, GooCanvasStyleProperty, i);
-      goo_canvas_style_set_property (copy, property->id, &property->value);
+      /* Basic drawing properties. */
+    case PROP_STROKE_PATTERN:
+      g_value_set_boxed (value, style->stroke_pattern);
+      break;
+    case PROP_FILL_PATTERN:
+      g_value_set_boxed (value, style->fill_pattern);
+      break;
+    case PROP_FILL_RULE:
+      g_value_set_enum (value, style->fill_rule);
+      break;
+    case PROP_OPERATOR:
+      g_value_set_enum (value, style->op);
+      break;
+    case PROP_ANTIALIAS:
+      g_value_set_enum (value, style->antialias);
+      break;
+
+      /* Line style & width properties. */
+    case PROP_LINE_WIDTH:
+      g_value_set_double (value, style->line_width);
+      break;
+    case PROP_LINE_CAP:
+      g_value_set_enum (value, style->line_cap);
+      break;
+    case PROP_LINE_JOIN:
+      g_value_set_enum (value, style->line_join);
+      break;
+    case PROP_LINE_JOIN_MITER_LIMIT:
+      g_value_set_double (value, style->line_join_miter_limit);
+      break;
+    case PROP_LINE_DASH:
+      g_value_set_boxed (value, style->dash);
+      break;
+
+      /* Font properties. */
+    case PROP_FONT:
+      if (style->font_desc)
+	font = pango_font_description_to_string (style->font_desc);
+      g_value_set_string (value, font);
+      g_free (font);
+      break;
+    case PROP_FONT_DESC:
+      g_value_set_boxed (value, style->font_desc);
+      break;
+    case PROP_HINT_METRICS:
+      g_value_set_enum (value, style->hint_metrics);
+      break;
+
+      /* Convenience properties. */
+    case PROP_STROKE_COLOR_RGBA:
+      goo_canvas_get_rgba_value_from_pattern (style->stroke_pattern, value);
+      break;
+    case PROP_FILL_COLOR_RGBA:
+      goo_canvas_get_rgba_value_from_pattern (style->fill_pattern, value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
-
-  return copy;
-}
-
-
-/**
- * goo_canvas_style_get_parent:
- * @style: a style.
- * 
- * Gets the parent of the style.
- * 
- * Returns: the parent of the given style, or %NULL.
- **/
-GooCanvasStyle*
-goo_canvas_style_get_parent         (GooCanvasStyle *style)
-{
-  return style->parent;
 }
 
 
-/**
- * goo_canvas_style_set_parent:
- * @style: a style.
- * @parent: the new parent.
- * 
- * Sets the parent of the style.
- **/
 void
-goo_canvas_style_set_parent         (GooCanvasStyle *style,
-				     GooCanvasStyle *parent)
+goo_canvas_style_set_stroke_pattern (GooCanvasStyle    *style,
+				     cairo_pattern_t   *pattern)
 {
-  if (style->parent == parent)
-    return;
-
-  if (style->parent)
-    g_object_unref (style->parent);
-
-  style->parent = parent;
-
-  if (style->parent)
-    g_object_ref (style->parent);
+  cairo_pattern_destroy (style->stroke_pattern);
+  style->stroke_pattern = pattern;
+  cairo_pattern_reference (style->stroke_pattern);
+  style->stroke_pattern_set = TRUE;
 }
 
 
-/**
- * goo_canvas_style_get_property:
- * @style: a style.
- * @property_id: the property identifier.
- * 
- * Gets the value of a property.
- *
- * This searches though all the #GooCanvasStyle's own list of property settings
- * and also all ancestor #GooCanvasStyle objects.
- *
- * Note that it returns a pointer to the internal #GValue setting, which should
- * not be changed.
- * 
- * Returns: the property value, or %NULL if it isn't set.
- **/
-GValue*
-goo_canvas_style_get_property       (GooCanvasStyle *style,
-				     GQuark          property_id)
+void
+goo_canvas_style_set_fill_pattern (GooCanvasStyle    *style,
+				   cairo_pattern_t   *pattern)
 {
-  GooCanvasStyleProperty *property;
-  gint i;
-
-  /* Step up the hierarchy of styles until we find the property. Note that
-     if style is passed in as NULL we simply return NULL. */
-  while (style)
-    {
-      for (i = 0; i < style->properties->len; i++)
-	{
-	  property = &g_array_index (style->properties, GooCanvasStyleProperty,
-				     i);
-	  if (property->id == property_id)
-	    return &property->value;
-	}
-
-      style = style->parent;
-    }
-
-  return NULL;
+  cairo_pattern_destroy (style->fill_pattern);
+  style->fill_pattern = pattern;
+  cairo_pattern_reference (style->fill_pattern);
+  style->fill_pattern_set = TRUE;
 }
 
 
-/**
- * goo_canvas_style_set_property:
- * @style: a style.
- * @property_id: the property identifier.
- * @value: the value of the property.
- * 
- * Sets a property in the style, replacing any current setting.
- *
- * Note that this will override the property setting in ancestor
- * #GooCanvasStyle objects.
- **/
-void
-goo_canvas_style_set_property	    (GooCanvasStyle *style,
-				     GQuark          property_id,
-				     const GValue   *value)
+static void
+goo_canvas_style_set_property (GObject              *object,
+			       guint                 prop_id,
+			       const GValue         *value,
+			       GParamSpec           *pspec)
 {
-  GooCanvasStyleProperty *property, new_property = { 0 };
-  gint i;
-
-  /* See if the property is already set. */
-  for (i = 0; i < style->properties->len; i++)
-    {
-      property = &g_array_index (style->properties, GooCanvasStyleProperty, i);
-      if (property->id == property_id)
-	{
-	  /* If the new value is NULL, remove the property setting, otherwise
-	     update the property value. */
-	  if (value)
-	    {
-	      g_value_copy (value, &property->value);
-	    }
-	  else
-	    {
-	      g_value_unset (&property->value);
-	      g_array_remove_index_fast (style->properties, i);
-	    }
-
-	  return;
-	}
-    }
+  GooCanvasStyle *style = (GooCanvasStyle*) object;
+  cairo_pattern_t *pattern;
+  const char *font_name;
+  PangoFontDescription *font_desc = NULL;
 
-  /* The property isn't set, so append a new property. */
-  if (value)
+  switch (prop_id)
     {
-      new_property.id = property_id;
-      g_value_init (&new_property.value, G_VALUE_TYPE (value));
-      g_value_copy (value, &new_property.value);
-      g_array_append_val (style->properties, new_property);
+      /* Basic drawing properties. */
+    case PROP_STROKE_PATTERN:
+      goo_canvas_style_set_stroke_pattern (style, g_value_get_boxed (value));
+      break;
+    case PROP_FILL_PATTERN:
+      goo_canvas_style_set_fill_pattern (style, g_value_get_boxed (value));
+      break;
+    case PROP_FILL_RULE:
+      style->fill_rule = g_value_get_enum (value);
+      break;
+    case PROP_OPERATOR:
+      style->op = g_value_get_enum (value);
+      break;
+    case PROP_ANTIALIAS:
+      style->antialias = g_value_get_enum (value);
+      break;
+
+      /* Line style & width properties. */
+    case PROP_LINE_WIDTH:
+      style->line_width = g_value_get_double (value);
+      break;
+    case PROP_LINE_CAP:
+      style->line_cap = g_value_get_enum (value);
+      break;
+    case PROP_LINE_JOIN:
+      style->line_join = g_value_get_enum (value);
+      break;
+    case PROP_LINE_JOIN_MITER_LIMIT:
+      style->line_join_miter_limit = g_value_get_double (value);
+      break;
+    case PROP_LINE_DASH:
+      goo_canvas_line_dash_unref (style->dash);
+      style->dash = g_value_get_boxed (value);
+      goo_canvas_line_dash_ref (style->dash);
+      break;
+
+      /* Font properties. */
+    case PROP_FONT:
+      if (style->font_desc)
+	pango_font_description_free (style->font_desc);
+      font_name = g_value_get_string (value);
+      if (font_name)
+	style->font_desc = pango_font_description_from_string (font_name);
+      else
+	style->font_desc = NULL;
+      break;
+    case PROP_FONT_DESC:
+      if (style->font_desc)
+	pango_font_description_free (style->font_desc);
+      font_desc = g_value_get_boxed (value);
+      if (font_desc)
+	style->font_desc = pango_font_description_copy (font_desc);
+      else
+	style->font_desc = NULL;
+      break;
+    case PROP_HINT_METRICS:
+      style->hint_metrics = g_value_get_enum (value);
+      break;
+
+      /* Convenience properties. */
+    case PROP_STROKE_COLOR:
+      pattern = goo_canvas_create_pattern_from_color_value (value);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+    case PROP_STROKE_COLOR_RGBA:
+      pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+    case PROP_STROKE_PIXBUF:
+      pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      goo_canvas_style_set_stroke_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+
+    case PROP_FILL_COLOR:
+      pattern = goo_canvas_create_pattern_from_color_value (value);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+    case PROP_FILL_COLOR_RGBA:
+      pattern = goo_canvas_create_pattern_from_rgba_value (value);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+    case PROP_FILL_PIXBUF:
+      pattern = goo_canvas_create_pattern_from_pixbuf_value (value);
+      goo_canvas_style_set_fill_pattern (style, pattern);
+      cairo_pattern_destroy (pattern);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
     }
 }
 
 
-/**
- * goo_canvas_style_set_stroke_options:
- * @style: a style.
- * @cr: a cairo context.
- * 
- * Sets the standard cairo stroke options using the given style.
- * 
- * Returns: %TRUE if a paint source is set, or %FALSE if the stroke should
- * be skipped.
- **/
-gboolean
-goo_canvas_style_set_stroke_options (GooCanvasStyle *style,
-				     cairo_t        *cr)
+static void
+goo_canvas_style_class_init (GooCanvasStyleClass *klass)
 {
-  GooCanvasStyleProperty *property;
-  gboolean operator_set = FALSE, antialias_set = FALSE;
-  gboolean stroke_pattern_set = FALSE, line_width_set = FALSE;
-  gboolean line_cap_set = FALSE, line_join_set = FALSE;
-  gboolean miter_limit_set = FALSE, line_dash_set = FALSE;
-  gboolean source_set = FALSE, need_stroke = TRUE;
-  gint i;
-
-  if (!style)
-    return TRUE;
-
-  /* Step up the hierarchy of styles looking for the properties. */
-  while (style)
-    {
-      for (i = 0; i < style->properties->len; i++)
-	{
-	  property = &g_array_index (style->properties, GooCanvasStyleProperty,
-				     i);
-
-	  if (property->id == goo_canvas_style_operator_id && !operator_set)
-	    {
-	      cairo_set_operator (cr, property->value.data[0].v_long);
-	      operator_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_antialias_id && !antialias_set)
-	    {
-	      cairo_set_antialias (cr, property->value.data[0].v_long);
-	      antialias_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_stroke_pattern_id && !stroke_pattern_set)
-	    {
-	      if (property->value.data[0].v_pointer)
-		{
-		  cairo_set_source (cr, property->value.data[0].v_pointer);
-		  source_set = TRUE;
-		}
-	      else
-		{
-		  /* If the stroke pattern has been explicitly set to NULL,
-		     then we don't need to do the stroke. */
-		  need_stroke = FALSE;
-		}
-	      stroke_pattern_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_line_width_id && !line_width_set)
-	    {
-	      cairo_set_line_width (cr, property->value.data[0].v_double);
-	      line_width_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_line_cap_id && !line_cap_set)
-	    {
-	      cairo_set_line_cap (cr, property->value.data[0].v_long);
-	      line_cap_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_line_join_id && !line_join_set)
-	    {
-	      cairo_set_line_join (cr, property->value.data[0].v_long);
-	      line_join_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_line_join_miter_limit_id && !miter_limit_set)
-	    {
-	      cairo_set_miter_limit (cr, property->value.data[0].v_double);
-	      miter_limit_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_line_dash_id && !line_dash_set)
-	    {
-	      GooCanvasLineDash *dash = property->value.data[0].v_pointer;
-	      if (dash)
-		cairo_set_dash (cr, dash->dashes, dash->num_dashes,
-				dash->dash_offset);
-	      else
-		cairo_set_dash (cr, NULL, 0, 0);
-	      line_dash_set = TRUE;
-	    }
-	}
-
-      style = style->parent;
-    }
+  GObjectClass *gobject_class = (GObjectClass*) klass;
 
-  /* If a stroke pattern hasn't been set in the style we reset the source to
-     black, just in case a fill pattern was used for the item. */
-  if (!source_set)
-    cairo_set_source_rgb (cr, 0, 0, 0);
+  gobject_class->finalize = goo_canvas_style_finalize;
 
-  return need_stroke;
+  gobject_class->get_property = goo_canvas_style_get_property;
+  gobject_class->set_property = goo_canvas_style_set_property;
+
+  /* Basic drawing properties. */
+  g_object_class_install_property (gobject_class, PROP_STROKE_PATTERN,
+                                   g_param_spec_boxed ("stroke-pattern",
+						       _("Stroke Pattern"),
+						       _("The pattern to use to paint the perimeter of the item, or NULL disable painting"),
+						       GOO_TYPE_CAIRO_PATTERN,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_FILL_PATTERN,
+                                   g_param_spec_boxed ("fill-pattern",
+						       _("Fill Pattern"),
+						       _("The pattern to use to paint the interior of the item, or NULL to disable painting"),
+						       GOO_TYPE_CAIRO_PATTERN,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_FILL_RULE,
+				   g_param_spec_enum ("fill-rule",
+						      _("Fill Rule"),
+						      _("The fill rule used to determine which parts of the item are filled"),
+						      GOO_TYPE_CAIRO_FILL_RULE,
+						      CAIRO_FILL_RULE_WINDING,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_OPERATOR,
+				   g_param_spec_enum ("operator",
+						      _("Operator"),
+						      _("The compositing operator to use"),
+						      GOO_TYPE_CAIRO_OPERATOR,
+						      CAIRO_OPERATOR_OVER,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_ANTIALIAS,
+				   g_param_spec_enum ("antialias",
+						      _("Antialias"),
+						      _("The antialiasing mode to use"),
+						      GOO_TYPE_CAIRO_ANTIALIAS,
+						      CAIRO_ANTIALIAS_GRAY,
+						      G_PARAM_READWRITE));
+
+  /* Line style & width properties. */
+  g_object_class_install_property (gobject_class, PROP_LINE_WIDTH,
+				   g_param_spec_double ("line-width",
+							_("Line Width"),
+							_("The line width to use for the item's perimeter"),
+							0.0, G_MAXDOUBLE, 2.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_LINE_CAP,
+				   g_param_spec_enum ("line-cap",
+						      _("Line Cap"),
+						      _("The line cap style to use"),
+						      GOO_TYPE_CAIRO_LINE_CAP,
+						      CAIRO_LINE_CAP_BUTT,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_LINE_JOIN,
+				   g_param_spec_enum ("line-join",
+						      _("Line Join"),
+						      _("The line join style to use"),
+						      GOO_TYPE_CAIRO_LINE_JOIN,
+						      CAIRO_LINE_JOIN_MITER,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_LINE_JOIN_MITER_LIMIT,
+				   g_param_spec_double ("line-join-miter-limit",
+							_("Miter Limit"),
+							_("The smallest angle to use with miter joins, in degrees. Bevel joins will be used below this limit"),
+							0.0, G_MAXDOUBLE, 10.0,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_LINE_DASH,
+				   g_param_spec_boxed ("line-dash",
+						       _("Line Dash"),
+						       _("The dash pattern to use"),
+						       GOO_TYPE_CANVAS_LINE_DASH,
+						       G_PARAM_READWRITE));
+
+  /* Font properties. */
+  g_object_class_install_property (gobject_class, PROP_FONT,
+				   g_param_spec_string ("font",
+							_("Font"),
+							_("The base font to use for the text"),
+							NULL,
+							G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_FONT_DESC,
+				   g_param_spec_boxed ("font-desc",
+						       _("Font Description"),
+						       _("The attributes specifying which font to use"),
+						       PANGO_TYPE_FONT_DESCRIPTION,
+						       G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_HINT_METRICS,
+				   g_param_spec_enum ("hint-metrics",
+						      _("Hint Metrics"),
+						      _("The hinting to be used for font metrics"),
+						      GOO_TYPE_CAIRO_HINT_METRICS,
+						      CAIRO_HINT_METRICS_OFF,
+						      G_PARAM_READWRITE));
+
+  /* Convenience properties - writable only. */
+  g_object_class_install_property (gobject_class, PROP_STROKE_COLOR,
+				   g_param_spec_string ("stroke-color",
+							_("Stroke Color"),
+							_("The color to use for the item's perimeter. To disable painting set the 'stroke-pattern' property to NULL"),
+							NULL,
+							G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_STROKE_COLOR_RGBA,
+				   g_param_spec_uint ("stroke-color-rgba",
+						      _("Stroke Color RGBA"),
+						      _("The color to use for the item's perimeter, specified as a 32-bit integer value. To disable painting set the 'stroke-pattern' property to NULL"),
+						      0, G_MAXUINT, 0,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_STROKE_PIXBUF,
+                                   g_param_spec_object ("stroke-pixbuf",
+							_("Stroke Pixbuf"),
+							_("The pixbuf to use to draw the item's perimeter. To disable painting set the 'stroke-pattern' property to NULL"),
+                                                        GDK_TYPE_PIXBUF,
+                                                        G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_FILL_COLOR,
+				   g_param_spec_string ("fill-color",
+							_("Fill Color"),
+							_("The color to use to paint the interior of the item. To disable painting set the 'fill-pattern' property to NULL"),
+							NULL,
+							G_PARAM_WRITABLE));
+
+  g_object_class_install_property (gobject_class, PROP_FILL_COLOR_RGBA,
+				   g_param_spec_uint ("fill-color-rgba",
+						      _("Fill Color RGBA"),
+						      _("The color to use to paint the interior of the item, specified as a 32-bit integer value. To disable painting set the 'fill-pattern' property to NULL"),
+						      0, G_MAXUINT, 0,
+						      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class, PROP_FILL_PIXBUF,
+                                   g_param_spec_object ("fill-pixbuf",
+							_("Fill Pixbuf"),
+							_("The pixbuf to use to paint the interior of the item. To disable painting set the 'fill-pattern' property to NULL"),
+                                                        GDK_TYPE_PIXBUF,
+                                                        G_PARAM_WRITABLE));
 }
 
 
-/**
- * goo_canvas_style_set_fill_options:
- * @style: a style.
- * @cr: a cairo context.
- * 
- * Sets the standard cairo fill options using the given style.
- * 
- * Returns: %TRUE if a paint source is set, or %FALSE if the fill should
- * be skipped.
- **/
-gboolean
-goo_canvas_style_set_fill_options   (GooCanvasStyle *style,
-				     cairo_t        *cr)
-{
-  GooCanvasStyleProperty *property;
-  gboolean operator_set = FALSE, antialias_set = FALSE;
-  gboolean fill_rule_set = FALSE, fill_pattern_set = FALSE;
-  gboolean need_fill = FALSE;
-  gint i;
-
-  if (!style)
-    return FALSE;
-
-  /* Step up the hierarchy of styles looking for the properties. */
-  while (style)
-    {
-      for (i = 0; i < style->properties->len; i++)
-	{
-	  property = &g_array_index (style->properties, GooCanvasStyleProperty,
-				     i);
-
-	  if (property->id == goo_canvas_style_operator_id && !operator_set)
-	    {
-	      cairo_set_operator (cr, property->value.data[0].v_long);
-	      operator_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_antialias_id && !antialias_set)
-	    {
-	      cairo_set_antialias (cr, property->value.data[0].v_long);
-	      antialias_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_fill_rule_id && !fill_rule_set)
-	    {
-	      cairo_set_fill_rule (cr, property->value.data[0].v_long);
-	      fill_rule_set = TRUE;
-	    }
-	  else if (property->id == goo_canvas_style_fill_pattern_id && !fill_pattern_set)
-	    {
-	      if (property->value.data[0].v_pointer)
-		{
-		  cairo_set_source (cr, property->value.data[0].v_pointer);
-		  need_fill = TRUE;
-		}
-	      fill_pattern_set = TRUE;
-	    }
-	}
-
-      style = style->parent;
-    }
-
-  return need_fill;
-}
diff --git a/src/goocanvasstyle.h b/src/goocanvasstyle.h
index ec76640..6b3c07d 100644
--- a/src/goocanvasstyle.h
+++ b/src/goocanvasstyle.h
@@ -1,47 +1,18 @@
 /*
- * GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
+ * GooCanvas. Copyright (C) 2005-2010 Damon Chaplin.
  * Released under the GNU LGPL license. See COPYING for details.
  *
- * goocanvasstyle.h - cascading styles.
+ * goocanvasstyle.h - 
  */
 #ifndef __GOO_CANVAS_STYLE_H__
 #define __GOO_CANVAS_STYLE_H__
 
 #include <gtk/gtk.h>
+#include <goocanvasutils.h>
 
 G_BEGIN_DECLS
 
 
-/* GQuarks for the basic properties. */
-extern GQuark goo_canvas_style_stroke_pattern_id;
-extern GQuark goo_canvas_style_fill_pattern_id;
-extern GQuark goo_canvas_style_fill_rule_id;
-extern GQuark goo_canvas_style_operator_id;
-extern GQuark goo_canvas_style_antialias_id;
-extern GQuark goo_canvas_style_line_width_id;
-extern GQuark goo_canvas_style_line_cap_id;
-extern GQuark goo_canvas_style_line_join_id;
-extern GQuark goo_canvas_style_line_join_miter_limit_id;
-extern GQuark goo_canvas_style_line_dash_id;
-extern GQuark goo_canvas_style_font_desc_id;
-extern GQuark goo_canvas_style_hint_metrics_id;
-
-
-/**
- * GooCanvasStyleProperty
- * @id: the unique property identifier.
- * @value: the value of the property.
- *
- * #GooCanvasStyleProperty represents a property setting.
- */
-typedef struct _GooCanvasStyleProperty GooCanvasStyleProperty;
-struct _GooCanvasStyleProperty
-{
-  GQuark id;
-  GValue value;
-};
-
-
 #define GOO_TYPE_CANVAS_STYLE            (goo_canvas_style_get_type ())
 #define GOO_CANVAS_STYLE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_CANVAS_STYLE, GooCanvasStyle))
 #define GOO_CANVAS_STYLE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_CANVAS_STYLE, GooCanvasStyleClass))
@@ -53,22 +24,28 @@ struct _GooCanvasStyleProperty
 typedef struct _GooCanvasStyle       GooCanvasStyle;
 typedef struct _GooCanvasStyleClass  GooCanvasStyleClass;
 
-/**
- * GooCanvasStyle
- * @parent: the parent style.
- * @properties: an array of #GooCanvasStyleProperty property settings.
- *
- * #GooCanvasStyle holds the style properties of a canvas item, as well as a
- * pointer to the parent style.
- */
 struct _GooCanvasStyle
 {
-  /* <private> */
   GObject parent_object;
 
-  /* <public> */
-  GooCanvasStyle *parent;
-  GArray *properties;
+  /*< private >*/
+  cairo_pattern_t *stroke_pattern;
+  cairo_pattern_t *fill_pattern;
+
+  GooCanvasLineDash *dash;
+  PangoFontDescription *font_desc;
+
+  gdouble line_width;
+  gdouble line_join_miter_limit;
+
+  guint stroke_pattern_set	    : 1;
+  guint fill_pattern_set	    : 1;
+  cairo_operator_t  op              : 6;
+  cairo_antialias_t antialias       : 4;
+  cairo_fill_rule_t fill_rule       : 3;
+  cairo_line_cap_t  line_cap        : 4;
+  cairo_line_join_t line_join       : 4;
+  guint hint_metrics		    : 2;
 };
 
 struct _GooCanvasStyleClass
@@ -85,25 +62,14 @@ struct _GooCanvasStyleClass
 };
 
 
-GType           goo_canvas_style_get_type           (void) G_GNUC_CONST;
-GooCanvasStyle* goo_canvas_style_new                (void);
-GooCanvasStyle* goo_canvas_style_copy               (GooCanvasStyle *style);
-
-GooCanvasStyle* goo_canvas_style_get_parent         (GooCanvasStyle *style);
-void            goo_canvas_style_set_parent         (GooCanvasStyle *style,
-						     GooCanvasStyle *parent);
+GType           goo_canvas_style_get_type          (void) G_GNUC_CONST;
+GooCanvasStyle* goo_canvas_style_new               (void);
 
-GValue*         goo_canvas_style_get_property       (GooCanvasStyle *style,
-						     GQuark          property_id);
-void            goo_canvas_style_set_property	    (GooCanvasStyle *style,
-						     GQuark          property_id,
-						     const GValue   *value);
+void         goo_canvas_style_set_stroke_pattern (GooCanvasStyle    *style,
+						  cairo_pattern_t   *pattern);
+void         goo_canvas_style_set_fill_pattern   (GooCanvasStyle    *style,
+						  cairo_pattern_t   *pattern);
 
-/* Convenience functions to set the standard cairo stroke and fill options. */
-gboolean        goo_canvas_style_set_stroke_options (GooCanvasStyle *style,
-						     cairo_t        *cr);
-gboolean        goo_canvas_style_set_fill_options   (GooCanvasStyle *style,
-						     cairo_t        *cr);
 
 G_END_DECLS
 
diff --git a/src/goocanvastable.c b/src/goocanvastable.c
index a2b2ccb..421d23e 100644
--- a/src/goocanvastable.c
+++ b/src/goocanvastable.c
@@ -1826,8 +1826,6 @@ goo_canvas_table_get_requested_area (GooCanvasItem        *item,
 
   simple->need_update = FALSE;
 
-  goo_canvas_item_simple_check_style (simple);
-
   if (simple->visibility == GOO_CANVAS_ITEM_HIDDEN)
     return FALSE;
 
@@ -2059,8 +2057,6 @@ goo_canvas_table_update  (GooCanvasItem   *item,
       simple->need_update = FALSE;
       simple->need_entire_subtree_update = FALSE;
 
-      goo_canvas_item_simple_check_style (simple);
-
       /* We just allocate exactly what is requested. */
       if (goo_canvas_table_get_requested_area (item, cr, &tmp_bounds))
 	{
@@ -2080,7 +2076,6 @@ goo_canvas_table_paint (GooCanvasItem         *item,
 			gdouble                scale)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
-  GooCanvasStyle *style = simple->style;
   GooCanvasGroup *group = (GooCanvasGroup*) item;
   GooCanvasTable *table = (GooCanvasTable*) item;
   GooCanvasTableLayoutData *layout_data = table->layout_data;
@@ -2153,7 +2148,7 @@ goo_canvas_table_paint (GooCanvasItem         *item,
   cairo_save (cr);
 
   /* Fill the table, if desired. */
-  if (goo_canvas_style_set_fill_options (style, cr))
+  if (goo_canvas_item_simple_set_fill_options (simple, cr))
     {
       cairo_rectangle (cr,
                        layout_data->border_width + vert_grid_line_width,
@@ -2165,7 +2160,7 @@ goo_canvas_table_paint (GooCanvasItem         *item,
 
   /* We use the style for the stroke color, but the line cap style and line
      width are overridden here. */
-  goo_canvas_style_set_stroke_options (style, cr);
+  goo_canvas_item_simple_set_stroke_options (simple, cr);
 
   cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
 
diff --git a/src/goocanvastext.c b/src/goocanvastext.c
index a8c69a9..e12398c 100644
--- a/src/goocanvastext.c
+++ b/src/goocanvastext.c
@@ -264,8 +264,6 @@ goo_canvas_text_create_layout (GooCanvasText           *text,
 			       gdouble	               *origin_y_return)
 {
   GooCanvasItemSimple *simple = (GooCanvasItemSimple*) text;
-  GooCanvasStyle *style = simple->style;
-  GValue *svalue;
   PangoLayout *layout;
   PangoContext *context;
   PangoRectangle ink_rect, logical_rect;
@@ -288,17 +286,12 @@ goo_canvas_text_create_layout (GooCanvasText           *text,
   else
     pango_layout_set_text (layout, string, -1);
 
-  svalue = goo_canvas_style_get_property (style,
-					  goo_canvas_style_font_desc_id);
-  if (svalue)
-    pango_layout_set_font_description (layout, svalue->data[0].v_pointer);
-
-  svalue = goo_canvas_style_get_property (style,
-					  goo_canvas_style_hint_metrics_id);
-  if (svalue)
-    hint_metrics = svalue->data[0].v_long;
+  if (simple->style && simple->style->font_desc)
+    pango_layout_set_font_description (layout, simple->style->font_desc);
 
   font_options = cairo_font_options_create ();
+  if (simple->style)
+    hint_metrics = simple->style->hint_metrics;
   cairo_font_options_set_hint_metrics (font_options, hint_metrics);
   pango_cairo_context_set_font_options (context, font_options);
   cairo_font_options_destroy (font_options);
@@ -432,27 +425,70 @@ goo_canvas_text_update  (GooCanvasItemSimple *simple,
      layout container and settings. */
   text->layout_width = text->width;
 
-  /* Compute the new bounds. */
-  layout = goo_canvas_text_create_layout (text, text->layout_width, cr,
-					  &simple->bounds, NULL, NULL);
-  g_object_unref (layout);
+  /* If the text is going to be clipped we can use the text's width and height
+     to calculate the bounds, which is much faster. */
+  if (text->width > 0.0 && text->height > 0.0)
+    {
+      simple->bounds.x1 = text->x;
+      simple->bounds.y1 = text->y;
 
-  /* If the height is set, use that. */
-  if (text->height > 0.0)
-    simple->bounds.y2 = simple->bounds.y1 + text->height;
+      switch (text->anchor)
+	{
+	case GTK_ANCHOR_N:
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_S:
+	  simple->bounds.x1 -= text->width / 2.0;
+	break;
+	case GTK_ANCHOR_NE:
+	case GTK_ANCHOR_E:
+	case GTK_ANCHOR_SE:
+	  simple->bounds.x1 -= text->width;
+	  break;
+	default:
+	  break;
+	}
+
+      switch (text->anchor)
+	{
+	case GTK_ANCHOR_W:
+	case GTK_ANCHOR_CENTER:
+	case GTK_ANCHOR_E:
+	  simple->bounds.y1 -= text->height / 2.0;
+	  break;
+	case GTK_ANCHOR_SW:
+	case GTK_ANCHOR_S:
+	case GTK_ANCHOR_SE:
+	  simple->bounds.y1 -= text->height;
+	  break;
+	default:
+	  break;
+	}
+
+      simple->bounds.x2 = simple->bounds.x1 + text->width;
+      simple->bounds.y2 = simple->bounds.y1 + text->height;
+    }
+  else
+    {
+      /* Compute the new bounds. */
+      layout = goo_canvas_text_create_layout (text, text->layout_width, cr,
+					      &simple->bounds, NULL, NULL);
+      g_object_unref (layout);
+
+      /* If the height is set, use that. */
+      if (text->height > 0.0)
+	simple->bounds.y2 = simple->bounds.y1 + text->height;
+    }
 }
 
 
 static gboolean
-goo_canvas_text_is_unpainted (GooCanvasStyle *style)
+goo_canvas_text_is_unpainted (GooCanvasText *text)
 {
-  GValue *value;
-
-  value = goo_canvas_style_get_property (style,
-					 goo_canvas_style_fill_pattern_id);
+  GooCanvasItemSimple *simple = (GooCanvasItemSimple*) text;
+  GooCanvasStyle *style = simple->style;
 
-  /* We only return TRUE if the value is explicitly set to NULL. */
-  if (value && !value->data[0].v_pointer)
+  /* We only return TRUE if the fill pattern is explicitly set to NULL. */
+  if (style && style->fill_pattern_set && !style->fill_pattern)
     return TRUE;
   return FALSE;
 }
@@ -481,7 +517,7 @@ goo_canvas_text_is_item_at (GooCanvasItemSimple *simple,
 
   if (is_pointer_event
       && simple->pointer_events & GOO_CANVAS_EVENTS_PAINTED_MASK
-      && goo_canvas_text_is_unpainted (simple->style))
+      && goo_canvas_text_is_unpainted (text))
     return FALSE;
 
   /* Check if the point is outside the clipped height. */
@@ -547,7 +583,7 @@ goo_canvas_text_paint (GooCanvasItemSimple   *simple,
   if (!text->text || !text->text[0])
     return;
 
-  goo_canvas_style_set_fill_options (simple->style, cr);
+  goo_canvas_item_simple_set_fill_options (simple, cr);
 
   cairo_new_path (cr);
   layout = goo_canvas_text_create_layout (text, text->layout_width, cr,
diff --git a/src/goocanvasutils.c b/src/goocanvasutils.c
index a2a64a2..e938255 100644
--- a/src/goocanvasutils.c
+++ b/src/goocanvasutils.c
@@ -1229,25 +1229,10 @@ goo_canvas_get_rgba_value_from_pattern (cairo_pattern_t *pattern,
 }
 
 
-/* Sets a style property to the given pattern, taking ownership of it. */
-void
-goo_canvas_set_style_property_from_pattern (GooCanvasStyle  *style,
-					    GQuark           property_id,
-					    cairo_pattern_t *pattern)
-{
-  GValue tmpval = { 0 };
-
-  g_value_init (&tmpval, GOO_TYPE_CAIRO_PATTERN);
-  g_value_take_boxed (&tmpval, pattern);
-  goo_canvas_style_set_property (style, property_id, &tmpval);
-  g_value_unset (&tmpval);
-}
-
-
 cairo_pattern_t*
 goo_canvas_create_pattern_from_color_value (const GValue *value)
 {
-  GdkColor color = { 0, 0, 0, 0, };
+  GdkColor color = { 0, 0, 0, 0 };
 
   if (g_value_get_string (value))
     gdk_color_parse (g_value_get_string (value), &color);



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