[dia] Bug 568168 - allow to render "holes" with some renderers



commit fe78bedf0c9ba782aa08cfecae62093ae65dc748
Author: Hans Breuer <hans breuer org>
Date:   Sun Oct 4 23:19:14 2009 +0200

    Bug 568168 - allow to render "holes" with some renderers
    
    A lot of Dia's bezier code has warnings like "only first BezPoint can be
    a BEZ_MOVE_TO". This is basically a limitation of the bezier approximation
    code originally used in the DiaGdkRenderer. It is currently used in the
    renderer base class DiaRenderer, but there already are some renderers in
    principle capable to handle move-to within bezier pathes just fine (cairo,
    svg, wmf, ...).
    Unfortuanetly also the XML format to serialize BezPoint has the hardcoded
    assumption of only one MOVE_TO at the beginning of the data. Although this
    is easily fixable by not using bezier(conn|shape)_(save|load) that would
    result in broken forward compatibility (older versions wont be able any
    longer to read bezier written with a newer version.
    So for the moment the rendering of holes is restricted to 'intermediate'
    rendering, e.g. the rendering of "Standard - Outline".
    
    2009-01-18  Hans Breuer  <hans breuer org>
    
     * lib/bezier_conn.c(bezierconn_simple_draw) : unused function adapted to
     split a given bezier rendering at the move-to points into 'easier' pieces
     (bezierconn_save) : add g_warning() about not first BEZ_MOVE_TO
     * lib/beziershape.c(beziershape_simple_draw) : unused function adapted to
     render only up to the first move-to within a bezier path with holes
     (beziershape_save) : add g_warning() about not first BEZ_MOVE_TO
     * lib/dia_svg.c(dia_svg_parse_path) : instead of splitting into pieces at
     move-to within a path just return the whole thing (disabled)
     * lib/geometry.c(distance_bez_(line|shape)_point,) : instead of
     complaining about "BEZ_MOVE_TO found halfway ..." just calculate it
     * lib/diarenderer.[ch] : DiaRenderer::is_capable_to(RENDER_HOLES) to
     allow objects code to adapt to specific renderer capabilities
     * objects/standard/outline.c : render holes if the renderer used is
     capable to do so. Otherwise fall back to rendering 'inner' shapes with
     color_white
     * plug-ins/cairo/diacairo-renderer.c
       plug-ins/libart/dialibartrenderer.c : implement Renderer::is_capabe_to
     * plug-ins/wmf/wmf.cpp : make it capable to render holes

 lib/bezier_conn.c                   |   17 +-
 lib/beziershape.c                   |   15 +
 lib/dia_svg.c                       |    7 +
 lib/diarenderer.c                   |   13 +
 lib/diarenderer.h                   |    8 +
 lib/geometry.c                      |    7 +-
 objects/standard/outline.c          | 1054 ++++++++++++++++++-----------------
 plug-ins/cairo/diacairo-renderer.c  |   13 +
 plug-ins/libart/dialibartrenderer.c |   12 +-
 plug-ins/wmf/wmf.cpp                |   96 +++-
 10 files changed, 692 insertions(+), 550 deletions(-)
---
diff --git a/lib/bezier_conn.c b/lib/bezier_conn.c
index 4f2070c..ea38be9 100644
--- a/lib/bezier_conn.c
+++ b/lib/bezier_conn.c
@@ -719,7 +719,20 @@ bezierconn_simple_draw(BezierConn *bez, DiaRenderer *renderer, real width)
   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_ROUND);
   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
 
-  DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, points, bez->numpoints, &color_black);
+  if (DIA_RENDERER_GET_CLASS(renderer)->is_capable_to(renderer, RENDER_HOLES)) {
+    DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, points, bez->numpoints, &color_black);
+  } else {
+    int i, from = 0, len;
+    
+    do {
+      for (i = from+1; i < bez->numpoints; ++i)
+        if (points[i].type == BEZ_MOVE_TO)
+          break;
+      len = i - from;
+      DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, &points[from], len, &color_black);
+      from += len;
+    } while (from < bez->numpoints);
+  }
 }
 
 /** Draw the control lines from the points of the bezier conn.
@@ -926,6 +939,8 @@ bezierconn_save(BezierConn *bez, ObjectNode obj_node)
   
   data_add_point(attr, &bez->points[0].p1);
   for (i = 1; i < bez->numpoints; i++) {
+    if (BEZ_MOVE_TO == bez->points[i].type)
+      g_warning("only first BezPoint can be a BEZ_MOVE_TO");
     data_add_point(attr, &bez->points[i].p1);
     data_add_point(attr, &bez->points[i].p2);
     data_add_point(attr, &bez->points[i].p3);
diff --git a/lib/beziershape.c b/lib/beziershape.c
index a1b4079..736d352 100644
--- a/lib/beziershape.c
+++ b/lib/beziershape.c
@@ -723,6 +723,7 @@ void
 beziershape_simple_draw(BezierShape *bezier, DiaRenderer *renderer, real width)
 {
   BezPoint *points;
+  int numpoints;
   
   g_assert(bezier != NULL);
   g_assert(renderer != NULL);
@@ -734,6 +735,18 @@ beziershape_simple_draw(BezierShape *bezier, DiaRenderer *renderer, real width)
   DIA_RENDERER_GET_CLASS(renderer)->set_linejoin(renderer, LINEJOIN_ROUND);
   DIA_RENDERER_GET_CLASS(renderer)->set_linecaps(renderer, LINECAPS_BUTT);
 
+  numpoints = bezier->numpoints;
+  if (!DIA_RENDERER_GET_CLASS(renderer)->is_capable_to(renderer, RENDER_HOLES)) {
+    /* just throw away everything from the second move */
+    int i;
+
+    for (i = 1; i < numpoints; ++i)
+      if (points[i].type == BEZ_MOVE_TO) {
+        numpoints = i;
+        break;
+      }
+  }
+
   DIA_RENDERER_GET_CLASS(renderer)->fill_bezier(renderer, points, bezier->numpoints,&color_white);
   DIA_RENDERER_GET_CLASS(renderer)->draw_bezier(renderer, points, bezier->numpoints,&color_black);
 }
@@ -929,6 +942,8 @@ beziershape_save(BezierShape *bezier, ObjectNode obj_node)
 
   data_add_point(attr, &bezier->points[0].p1);
   for (i = 1; i < bezier->numpoints; i++) {
+    if (BEZ_MOVE_TO == bezier->points[i].type)
+      g_warning("only first BezPoint can be a BEZ_MOVE_TO");
     data_add_point(attr, &bezier->points[i].p1);
     data_add_point(attr, &bezier->points[i].p2);
     if (i < bezier->numpoints - 1)
diff --git a/lib/dia_svg.c b/lib/dia_svg.c
index cef259b..96c95d5 100644
--- a/lib/dia_svg.c
+++ b/lib/dia_svg.c
@@ -581,20 +581,25 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed)
     /* check for a new command */
     switch (path[0]) {
     case 'M':
+#undef MULTI_MOVE_BEZIER /* Dia XML serialization can't cope with it */
+#ifndef MULTI_MOVE_BEZIER
       if (points->len > 0) {
 	need_next_element = TRUE;
 	goto MORETOPARSE;
       }
+#endif
       path++;
       path_chomp(path);
       last_type = PATH_MOVE;
       last_relative = FALSE;
       break;
     case 'm':
+#ifndef MULTI_MOVE_BEZIER
       if (points->len > 0) {
 	need_next_element = TRUE;
 	goto MORETOPARSE;
       }
+#endif
       path++;
       path_chomp(path);
       last_type = PATH_MOVE;
@@ -861,7 +866,9 @@ dia_svg_parse_path(const gchar *path_str, gchar **unparsed, gboolean *closed)
 	g_array_append_val(points, bez);
       }
       *closed = TRUE;
+#ifndef MULTI_MOVE_BEZIER
       need_next_element = TRUE;
+#endif
     }
     /* get rid of any ignorable characters */
     path_chomp(path);
diff --git a/lib/diarenderer.c b/lib/diarenderer.c
index 73bb21d..9ce063a 100644
--- a/lib/diarenderer.c
+++ b/lib/diarenderer.c
@@ -170,6 +170,8 @@ static void draw_bezier_with_arrows (DiaRenderer *renderer,
                                     Arrow *start_arrow,
                                     Arrow *end_arrow);
 
+static gboolean is_capable_to (DiaRenderer *renderer, RenderCapability cap);
+
 static gpointer parent_class = NULL;
 
 GType
@@ -279,6 +281,9 @@ dia_renderer_class_init (DiaRendererClass *klass)
   renderer_class->draw_polyline_with_arrows = draw_polyline_with_arrows;
   renderer_class->draw_rounded_polyline_with_arrows = draw_rounded_polyline_with_arrows;
   renderer_class->draw_bezier_with_arrows = draw_bezier_with_arrows;
+  
+  /* other */
+  renderer_class->is_capable_to = is_capable_to;
 }
 
 static void 
@@ -1452,6 +1457,14 @@ get_height_pixels (DiaRenderer *renderer)
   return 0;
 }
 
+/*!
+ * The base class has none of the advanced capabilities
+ */
+static gboolean 
+is_capable_to (DiaRenderer *renderer, RenderCapability cap)
+{
+  return FALSE;
+}
 
 /*
  * non member functions
diff --git a/lib/diarenderer.h b/lib/diarenderer.h
index 22fda68..0e5f706 100644
--- a/lib/diarenderer.h
+++ b/lib/diarenderer.h
@@ -31,6 +31,11 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+  RENDER_HOLES = (1<<0),
+  RENDER_ALPHA = (1<<1)
+} RenderCapability;
+
 /*! GObject boiler plate, create runtime information */
 #define DIA_TYPE_RENDERER           (dia_renderer_get_type ())
 /*! GObject boiler plate, a safe type cast */
@@ -253,6 +258,9 @@ struct _DiaRendererClass
                                    Color *color,
                                    Arrow *start_arrow,
                                    Arrow *end_arrow);
+  /*! allows to adapt DiaObject implementations to certain renderer capabilities */
+  gboolean (*is_capable_to) (DiaRenderer *renderer,
+			     RenderCapability cap);
 };
 
 /*
diff --git a/lib/geometry.c b/lib/geometry.c
index a590296..b6b3a04 100644
--- a/lib/geometry.c
+++ b/lib/geometry.c
@@ -328,8 +328,7 @@ distance_bez_line_point(const BezPoint *b, guint npoints,
 
     switch (b[i].type) {
     case BEZ_MOVE_TO:
-      /*g_assert_not_reached();*/
-      g_warning("BEZ_MOVE_TO found half way through a bezier line");
+      last = b[i].p1;
       break;
     case BEZ_LINE_TO:
       dist = distance_line_point(&last, &b[i].p1, line_width, point);
@@ -366,8 +365,8 @@ distance_bez_shape_point(const BezPoint *b, guint npoints,
 
     switch (b[i].type) {
     case BEZ_MOVE_TO:
-      /*g_assert_not_reached();*/
-      g_warning("BEZ_MOVE_TO found half way through a bezier shape");
+      /* no complains, there are renderers capable to handle this */
+      last = b[i].p1;
       break;
     case BEZ_LINE_TO:
       dist = distance_line_point(&last, &b[i].p1, line_width, point);
diff --git a/objects/standard/outline.c b/objects/standard/outline.c
index 002ca21..7e3dc31 100644
--- a/objects/standard/outline.c
+++ b/objects/standard/outline.c
@@ -1,542 +1,550 @@
-/* Dia -- an diagram creation/manipulation program
- * Copyright (C) 1998 Alexander Larsson
- *
- * outline.c -- cairo based rotateable outline
- * Copyright (C) 2007, Hans Breuer, <Hans Breuer Org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/*!
- * A prototype for text effects with the standard renderer interface.
- * It should be possible to do all those fancy text effects like outline, rotate, ...
- * by converting text to pathes before rendering.
- */
-#include <config.h>
-
-#include "object.h"
-#include "diarenderer.h"
-#include "attributes.h"
-#include "properties.h"
-#include "boundingbox.h"
-
-#include "tool-icons.h"
+/* Dia -- an diagram creation/manipulation program
+ * Copyright (C) 1998 Alexander Larsson
+ *
+ * outline.c -- cairo based rotateable outline
+ * Copyright (C) 2007, Hans Breuer, <Hans Breuer Org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*!
+ * A prototype for text effects with the standard renderer interface.
+ * It should be possible to do all those fancy text effects like outline, rotate, ...
+ * by converting text to pathes before rendering.
+ */
+#include <config.h>
+
+#include "object.h"
+#include "diarenderer.h"
+#include "attributes.h"
+#include "properties.h"
+#include "boundingbox.h"
+
+#include "tool-icons.h"
 
 #ifdef HAVE_CAIRO
 #include <cairo.h>
 
-#ifdef CAIRO_HAS_SVG_SURFACE 
+#ifdef CAIRO_HAS_SVG_SURFACE 
 #include <cairo-svg.h>
-#endif
-
-#define NUM_HANDLES 2
-/* Object definition */
-typedef struct _Outline {
-  DiaObject object;
-  
-  char *name;
-  real rotation;
-
-  DiaFont *font;
-  real font_height;
-
-  Color line_color;
-  Color fill_color;
-  gboolean show_background;
-  real line_width;
-  
-  Handle handles[NUM_HANDLES];
-  /* calculated data */
+#endif
+
+#define NUM_HANDLES 2
+/* Object definition */
+typedef struct _Outline {
+  DiaObject object;
+  
+  char *name;
+  real rotation;
+
+  DiaFont *font;
+  real font_height;
+
+  Color line_color;
+  Color fill_color;
+  gboolean show_background;
+  real line_width;
+  
+  Handle handles[NUM_HANDLES];
+  /* calculated data */
   Point ink_rect[4];
   cairo_path_t *path;
-  struct _Matrix
-  {
-    real xx;
-    real xy;
-    real yx;
-    real yy;
-  } mat;
-} Outline;
-
-/* Type definition */
-static DiaObject *outline_create (Point *startpoint,
-				  void *user_data,
-				  Handle **handle1,
-				  Handle **handle2);
-static DiaObject *
-outline_load(ObjectNode obj_node, int version, const char *filename);
-
-static ObjectTypeOps outline_type_ops =
-{
-  (CreateFunc)outline_create,
-  (LoadFunc)  outline_load,
-  (SaveFunc)  object_save_using_properties, /* outline_save */
-  (GetDefaultsFunc)   NULL,
-  (ApplyDefaultsFunc) NULL
-};
-
-static DiaObjectType outline_type =
-{
-  "Standard - Outline",   /* name */
-  0,                      /* version */
-  (char **) outline_icon, /* pixmap */
-  
-  &outline_type_ops,      /* ops */
-  NULL,                   /* pixmap_file */
-  0                       /* default_user_data */
-};
-
-/* make accesible from the outside for type regristation */
-DiaObjectType *_outline_type = (DiaObjectType *) &outline_type;
-
-/* Class definition */
-static ObjectChange* outline_move_handle (Outline *outline,
-                                          Handle *handle,
-					  Point *to, ConnectionPoint *cp,
-					  HandleMoveReason reason, ModifierKeys modifiers);
-static ObjectChange* outline_move (Outline *outline, Point *to);
-static void outline_select(Outline *outline, Point *clicked_point,
-			   DiaRenderer *interactive_renderer);
-static void outline_draw(Outline *outline, DiaRenderer *renderer);
-static real outline_distance_from (Outline *outline, Point *point);
-static void outline_update_data (Outline *outline);
-static void outline_destroy (Outline *outline);
-static DiaObject *outline_copy (Outline *outline);
-static DiaMenu *outline_get_object_menu(Outline *outline,
-					Point *clickedpoint);
-static PropDescription *outline_describe_props(Outline *outline);
-static void outline_get_props(Outline *outline, GPtrArray *props);
-static void outline_set_props(Outline *outline, GPtrArray *props);
-
-static ObjectOps outline_ops = {
-  (DestroyFunc)         outline_destroy,
-  (DrawFunc)            outline_draw,
-  (DistanceFunc)        outline_distance_from,
-  (SelectFunc)          outline_select,
-  (CopyFunc)            outline_copy,
-  (MoveFunc)            outline_move,
-  (MoveHandleFunc)      outline_move_handle,
-  (GetPropertiesFunc)   object_create_props_dialog,
-  (ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
-  (ObjectMenuFunc)      outline_get_object_menu,
-  (DescribePropsFunc)   outline_describe_props,
-  (GetPropsFunc)        outline_get_props,
-  (SetPropsFunc)        outline_set_props,
-  (TextEditFunc) 0,
-  (ApplyPropertiesListFunc) object_apply_props,
-};
-
-/* Type implementation */
-static void
-outline_init_handles (Outline *outline)
-{
-  DiaObject *obj = &outline->object;
-  int i;
-  
-  for (i = 0; i < NUM_HANDLES; ++i) {
-    obj->handles[i] = &outline->handles[i];
-    obj->handles[i]->type = HANDLE_MAJOR_CONTROL;
-    obj->handles[i]->connect_type = HANDLE_CONNECTABLE;
-    obj->handles[i]->connected_to = NULL;
-  }
-}
-
-/*! Factory function - create default object */
-static DiaObject *
-outline_create (Point *startpoint,
-		void *user_data,
-		Handle **handle1,
-		Handle **handle2)
-{
-  Outline *outline;
-  DiaObject *obj;
-  
-  outline = g_new0 (Outline,1);
-  obj = &outline->object;
-  obj->type = &outline_type;
-  obj->ops = &outline_ops;
-
-  object_init (obj, NUM_HANDLES, 0);
-  obj->position = *startpoint;
-
-  outline_init_handles (outline);
-  
-  attributes_get_default_font (&outline->font, &outline->font_height);
-
-  outline->line_width = 0; /* Not: attributes_get_default_linewidth(); it looks ugly */
-  outline->line_color = attributes_get_foreground();
-  outline->fill_color = attributes_get_background();
-  outline->show_background = FALSE;
-  outline->name = g_strdup ("?");
-  outline->rotation = 0;
-
-  *handle1 = outline->object.handles[0];
-  *handle2 = outline->object.handles[1];
-
-  outline_update_data (outline);
-
-  return obj;
-}
-static DiaObject *
-outline_load(ObjectNode obj_node, int version, const char *filename)
-{
-  return object_load_using_properties(&outline_type,
-                                      obj_node,version,filename);
-}
-
-/* Class/Object implementation */
-static PropNumData _rotation_range = { 0.0f, 360.0f, 1.0f };
-static PropDescription outline_props[] = {
-  OBJECT_COMMON_PROPERTIES,
-  { "name", PROP_TYPE_STRING,PROP_FLAG_VISIBLE|PROP_FLAG_DONT_MERGE, 
-    N_("Text content"),NULL },
-  { "rotation", PROP_TYPE_REAL,PROP_FLAG_VISIBLE,
-    N_("Rotation"), N_("Angle to rotate the outline"), &_rotation_range},
-  /* the default PROP_STD_TEXT_FONT has PROP_FLAG_DONT_SAVE, we need saving */
-  PROP_STD_TEXT_FONT_OPTIONS(PROP_FLAG_VISIBLE),
-  PROP_STD_TEXT_HEIGHT_OPTIONS(PROP_FLAG_VISIBLE),
-  PROP_STD_LINE_WIDTH,
-  PROP_STD_LINE_COLOUR,
-  PROP_STD_FILL_COLOUR,
-  PROP_STD_SHOW_BACKGROUND,
-  PROP_DESC_END
-};
-
-static PropOffset outline_offsets[] = {
-  OBJECT_COMMON_PROPERTIES_OFFSETS,
-  { "name", PROP_TYPE_STRING, offsetof(Outline, name) },
-  { "rotation", PROP_TYPE_REAL, offsetof(Outline, rotation) },
-  { "text_font",PROP_TYPE_FONT,offsetof(Outline,font) },
-  { PROP_STDNAME_TEXT_HEIGHT,PROP_STDTYPE_TEXT_HEIGHT,offsetof(Outline, font_height) },
-  { PROP_STDNAME_LINE_WIDTH, PROP_STDTYPE_LINE_WIDTH, offsetof(Outline, line_width) },
-  { "line_colour", PROP_TYPE_COLOUR, offsetof(Outline, line_color) },
-  { "fill_colour", PROP_TYPE_COLOUR, offsetof(Outline, fill_color) },
-  { "show_background", PROP_TYPE_BOOL, offsetof(Outline, show_background) },
-  { NULL, 0, 0 }
-};
+  struct _Matrix
+  {
+    real xx;
+    real xy;
+    real yx;
+    real yy;
+  } mat;
+} Outline;
+
+/* Type definition */
+static DiaObject *outline_create (Point *startpoint,
+				  void *user_data,
+				  Handle **handle1,
+				  Handle **handle2);
+static DiaObject *
+outline_load(ObjectNode obj_node, int version, const char *filename);
+
+static ObjectTypeOps outline_type_ops =
+{
+  (CreateFunc)outline_create,
+  (LoadFunc)  outline_load,
+  (SaveFunc)  object_save_using_properties, /* outline_save */
+  (GetDefaultsFunc)   NULL,
+  (ApplyDefaultsFunc) NULL
+};
+
+static DiaObjectType outline_type =
+{
+  "Standard - Outline",   /* name */
+  0,                      /* version */
+  (char **) outline_icon, /* pixmap */
+  
+  &outline_type_ops,      /* ops */
+  NULL,                   /* pixmap_file */
+  0                       /* default_user_data */
+};
+
+/* make accesible from the outside for type regristation */
+DiaObjectType *_outline_type = (DiaObjectType *) &outline_type;
+
+/* Class definition */
+static ObjectChange* outline_move_handle (Outline *outline,
+                                          Handle *handle,
+					  Point *to, ConnectionPoint *cp,
+					  HandleMoveReason reason, ModifierKeys modifiers);
+static ObjectChange* outline_move (Outline *outline, Point *to);
+static void outline_select(Outline *outline, Point *clicked_point,
+			   DiaRenderer *interactive_renderer);
+static void outline_draw(Outline *outline, DiaRenderer *renderer);
+static real outline_distance_from (Outline *outline, Point *point);
+static void outline_update_data (Outline *outline);
+static void outline_destroy (Outline *outline);
+static DiaObject *outline_copy (Outline *outline);
+static DiaMenu *outline_get_object_menu(Outline *outline,
+					Point *clickedpoint);
+static PropDescription *outline_describe_props(Outline *outline);
+static void outline_get_props(Outline *outline, GPtrArray *props);
+static void outline_set_props(Outline *outline, GPtrArray *props);
+
+static ObjectOps outline_ops = {
+  (DestroyFunc)         outline_destroy,
+  (DrawFunc)            outline_draw,
+  (DistanceFunc)        outline_distance_from,
+  (SelectFunc)          outline_select,
+  (CopyFunc)            outline_copy,
+  (MoveFunc)            outline_move,
+  (MoveHandleFunc)      outline_move_handle,
+  (GetPropertiesFunc)   object_create_props_dialog,
+  (ApplyPropertiesDialogFunc) object_apply_props_from_dialog,
+  (ObjectMenuFunc)      outline_get_object_menu,
+  (DescribePropsFunc)   outline_describe_props,
+  (GetPropsFunc)        outline_get_props,
+  (SetPropsFunc)        outline_set_props,
+  (TextEditFunc) 0,
+  (ApplyPropertiesListFunc) object_apply_props,
+};
+
+/* Type implementation */
+static void
+outline_init_handles (Outline *outline)
+{
+  DiaObject *obj = &outline->object;
+  int i;
+  
+  for (i = 0; i < NUM_HANDLES; ++i) {
+    obj->handles[i] = &outline->handles[i];
+    obj->handles[i]->type = HANDLE_MAJOR_CONTROL;
+    obj->handles[i]->connect_type = HANDLE_CONNECTABLE;
+    obj->handles[i]->connected_to = NULL;
+  }
+}
+
+/*! Factory function - create default object */
+static DiaObject *
+outline_create (Point *startpoint,
+		void *user_data,
+		Handle **handle1,
+		Handle **handle2)
+{
+  Outline *outline;
+  DiaObject *obj;
+  
+  outline = g_new0 (Outline,1);
+  obj = &outline->object;
+  obj->type = &outline_type;
+  obj->ops = &outline_ops;
+
+  object_init (obj, NUM_HANDLES, 0);
+  obj->position = *startpoint;
+
+  outline_init_handles (outline);
+  
+  attributes_get_default_font (&outline->font, &outline->font_height);
+
+  outline->line_width = 0; /* Not: attributes_get_default_linewidth(); it looks ugly */
+  outline->line_color = attributes_get_foreground();
+  outline->fill_color = attributes_get_background();
+  outline->show_background = FALSE;
+  outline->name = g_strdup ("?");
+  outline->rotation = 0;
+
+  *handle1 = outline->object.handles[0];
+  *handle2 = outline->object.handles[1];
+
+  outline_update_data (outline);
+
+  return obj;
+}
+static DiaObject *
+outline_load(ObjectNode obj_node, int version, const char *filename)
+{
+  return object_load_using_properties(&outline_type,
+                                      obj_node,version,filename);
+}
+
+/* Class/Object implementation */
+static PropNumData _rotation_range = { 0.0f, 360.0f, 1.0f };
+static PropDescription outline_props[] = {
+  OBJECT_COMMON_PROPERTIES,
+  { "name", PROP_TYPE_STRING,PROP_FLAG_VISIBLE|PROP_FLAG_DONT_MERGE, 
+    N_("Text content"),NULL },
+  { "rotation", PROP_TYPE_REAL,PROP_FLAG_VISIBLE,
+    N_("Rotation"), N_("Angle to rotate the outline"), &_rotation_range},
+  /* the default PROP_STD_TEXT_FONT has PROP_FLAG_DONT_SAVE, we need saving */
+  PROP_STD_TEXT_FONT_OPTIONS(PROP_FLAG_VISIBLE),
+  PROP_STD_TEXT_HEIGHT_OPTIONS(PROP_FLAG_VISIBLE),
+  PROP_STD_LINE_WIDTH,
+  PROP_STD_LINE_COLOUR,
+  PROP_STD_FILL_COLOUR,
+  PROP_STD_SHOW_BACKGROUND,
+  PROP_DESC_END
+};
+
+static PropOffset outline_offsets[] = {
+  OBJECT_COMMON_PROPERTIES_OFFSETS,
+  { "name", PROP_TYPE_STRING, offsetof(Outline, name) },
+  { "rotation", PROP_TYPE_REAL, offsetof(Outline, rotation) },
+  { "text_font",PROP_TYPE_FONT,offsetof(Outline,font) },
+  { PROP_STDNAME_TEXT_HEIGHT,PROP_STDTYPE_TEXT_HEIGHT,offsetof(Outline, font_height) },
+  { PROP_STDNAME_LINE_WIDTH, PROP_STDTYPE_LINE_WIDTH, offsetof(Outline, line_width) },
+  { "line_colour", PROP_TYPE_COLOUR, offsetof(Outline, line_color) },
+  { "fill_colour", PROP_TYPE_COLOUR, offsetof(Outline, fill_color) },
+  { "show_background", PROP_TYPE_BOOL, offsetof(Outline, show_background) },
+  { NULL, 0, 0 }
+};
 /* empty write function */
-static cairo_status_t
-write_nul (void                *closure,
-           const unsigned char *data,
-	   unsigned int	        length)
-{
-  return CAIRO_STATUS_SUCCESS;
+static cairo_status_t
+write_nul (void                *closure,
+           const unsigned char *data,
+	   unsigned int	        length)
+{
+  return CAIRO_STATUS_SUCCESS;
 }
-/*! Not in the object interface but still required */
-static void
-outine_update_handles(Outline *outline)
-{
-  DiaObject *obj = &outline->object;
-
-  g_return_if_fail (obj->handles != NULL);
-  obj->handles[0]->id = HANDLE_RESIZE_NW;
-  obj->handles[0]->pos = outline->ink_rect[0];
-
-  obj->handles[1]->id = HANDLE_RESIZE_SE;
-  obj->handles[1]->pos = outline->ink_rect[2];
-}
-/*! Not in the object interface but very important anyway. Used to recalculate the object data after a change  */
-static void
-outline_update_data (Outline *outline)
-{
-  DiaObject *obj = &outline->object;
+/*! Not in the object interface but still required */
+static void
+outine_update_handles(Outline *outline)
+{
+  DiaObject *obj = &outline->object;
+
+  g_return_if_fail (obj->handles != NULL);
+  obj->handles[0]->id = HANDLE_RESIZE_NW;
+  obj->handles[0]->pos = outline->ink_rect[0];
+
+  obj->handles[1]->id = HANDLE_RESIZE_SE;
+  obj->handles[1]->pos = outline->ink_rect[2];
+}
+/*! Not in the object interface but very important anyway. Used to recalculate the object data after a change  */
+static void
+outline_update_data (Outline *outline)
+{
+  DiaObject *obj = &outline->object;
   /* calculate the ink_rect from two points and the given rotation */
-  cairo_t *cr;
-  cairo_surface_t *surface;
-  cairo_text_extents_t extents;
-  real x, y;
-  DiaFontStyle style;
-
-  if (outline->path)
-    cairo_path_destroy (outline->path);
-  outline->path = NULL;
+  cairo_t *cr;
+  cairo_surface_t *surface;
+  cairo_text_extents_t extents;
+  real x, y;
+  DiaFontStyle style;
+
+  if (outline->path)
+    cairo_path_destroy (outline->path);
+  outline->path = NULL;
   /* surface will not be used to render anything, it is just to create the cairo context */
-#ifdef CAIRO_HAS_SVG_SURFACE
+#ifdef CAIRO_HAS_SVG_SURFACE
   surface = cairo_svg_surface_create_for_stream (write_nul, NULL, 100, 100);
 #else
   /* if only I could remember why I have choosen the svg surface in the first place */
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 100, 100);
-#endif
-  cr = cairo_create (surface);
-  cairo_surface_destroy (surface); /* in fact: unref() */
-  style = dia_font_get_style (outline->font);
-  /* not exact matching but almost the best we can do with the toy api */
-  cairo_select_font_face (cr, dia_font_get_family (outline->font), 
-                          DIA_FONT_STYLE_GET_SLANT (style) == DIA_FONT_NORMAL ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_SLANT_ITALIC,
-                          DIA_FONT_STYLE_GET_WEIGHT (style) < DIA_FONT_MEDIUM ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
-  cairo_set_font_size (cr, outline->font_height);
-  cairo_text_extents (cr, outline->name, &extents);
-
-  /* unfortunately this has no effect on the returned path? See below. */
-  cairo_rotate (cr, outline->rotation/(2*G_PI));
-
-  outline->mat.xx =  cos(G_PI*outline->rotation/180);
-  outline->mat.xy =  sin(G_PI*outline->rotation/180);
-  outline->mat.yx = -sin(G_PI*outline->rotation/180);
-  outline->mat.yy =  cos(G_PI*outline->rotation/180);
-
-  /* fix point */
-  outline->ink_rect[0].x = x = obj->position.x;
-  outline->ink_rect[0].y = y = obj->position.y;  
-  /* handle rotation */
-  outline->ink_rect[1].x = x + extents.width * outline->mat.xx;
-  outline->ink_rect[1].y = y + extents.width * outline->mat.yx;
-  outline->ink_rect[2].x = x + extents.width * outline->mat.xx + extents.height * outline->mat.xy;
-  outline->ink_rect[2].y = y + extents.width * outline->mat.yx + extents.height * outline->mat.yy;
-  outline->ink_rect[3].x = x + extents.height * outline->mat.xy;
-  outline->ink_rect[3].y = y + extents.height * outline->mat.yy;
-  /* x_advance? */
-  /* calculate bounding box */
-  {
-    PolyBBExtras bbex = {0, 0, outline->line_width/2, 0, 0 };
-    polyline_bbox (&outline->ink_rect[0], 4, &bbex, TRUE, &obj->bounding_box);
-  }
-
-  outine_update_handles (outline),
-
-  cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing);
-
-#if 0
-  /* reset the matrix to not yet change the outline_draw method */
-  outline->mat.xx =  1.0;
-  outline->mat.xy =  0.0;
-  outline->mat.yx =  0.0;
-  outline->mat.yy =  1.0;
-#endif
-
-  cairo_text_path (cr, outline->name);
-  /* reset the rotation to not have the path rotated back and forth: no effect */
-  cairo_rotate (cr, 0.0);
-  outline->path = cairo_copy_path (cr);
-  /* the cairo context is only used in this fuinction */
+#endif
+  cr = cairo_create (surface);
+  cairo_surface_destroy (surface); /* in fact: unref() */
+  style = dia_font_get_style (outline->font);
+  /* not exact matching but almost the best we can do with the toy api */
+  cairo_select_font_face (cr, dia_font_get_family (outline->font), 
+                          DIA_FONT_STYLE_GET_SLANT (style) == DIA_FONT_NORMAL ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_SLANT_ITALIC,
+                          DIA_FONT_STYLE_GET_WEIGHT (style) < DIA_FONT_MEDIUM ? CAIRO_FONT_SLANT_NORMAL : CAIRO_FONT_WEIGHT_BOLD);
+  cairo_set_font_size (cr, outline->font_height);
+  cairo_text_extents (cr, outline->name, &extents);
+
+  /* unfortunately this has no effect on the returned path? See below. */
+  cairo_rotate (cr, outline->rotation/(2*G_PI));
+
+  outline->mat.xx =  cos(G_PI*outline->rotation/180);
+  outline->mat.xy =  sin(G_PI*outline->rotation/180);
+  outline->mat.yx = -sin(G_PI*outline->rotation/180);
+  outline->mat.yy =  cos(G_PI*outline->rotation/180);
+
+  /* fix point */
+  outline->ink_rect[0].x = x = obj->position.x;
+  outline->ink_rect[0].y = y = obj->position.y;  
+  /* handle rotation */
+  outline->ink_rect[1].x = x + extents.width * outline->mat.xx;
+  outline->ink_rect[1].y = y + extents.width * outline->mat.yx;
+  outline->ink_rect[2].x = x + extents.width * outline->mat.xx + extents.height * outline->mat.xy;
+  outline->ink_rect[2].y = y + extents.width * outline->mat.yx + extents.height * outline->mat.yy;
+  outline->ink_rect[3].x = x + extents.height * outline->mat.xy;
+  outline->ink_rect[3].y = y + extents.height * outline->mat.yy;
+  /* x_advance? */
+  /* calculate bounding box */
+  {
+    PolyBBExtras bbex = {0, 0, outline->line_width/2, 0, 0 };
+    polyline_bbox (&outline->ink_rect[0], 4, &bbex, TRUE, &obj->bounding_box);
+  }
+
+  outine_update_handles (outline),
+
+  cairo_move_to (cr, -extents.x_bearing, -extents.y_bearing);
+
+#if 0
+  /* reset the matrix to not yet change the outline_draw method */
+  outline->mat.xx =  1.0;
+  outline->mat.xy =  0.0;
+  outline->mat.yx =  0.0;
+  outline->mat.yy =  1.0;
+#endif
+
+  cairo_text_path (cr, outline->name);
+  /* reset the rotation to not have the path rotated back and forth: no effect */
+  cairo_rotate (cr, 0.0);
+  outline->path = cairo_copy_path (cr);
+  /* the cairo context is only used in this fuinction */
   cairo_destroy (cr);
-}
-static void 
-outline_draw(Outline *outline, DiaRenderer *renderer)
-{
-  DiaObject *obj = &outline->object;
-  int i, n = 0, total;
-  BezPoint *pts;
-  real x, y;
-  Point ps = {0, 0}; /* silence gcc */
-  
-  if (!outline->path)
-    return;
-  DIA_RENDERER_GET_CLASS (renderer)->set_linewidth (renderer, outline->line_width);
-  DIA_RENDERER_GET_CLASS (renderer)->set_linestyle (renderer, LINESTYLE_SOLID);
-  DIA_RENDERER_GET_CLASS (renderer)->set_linejoin(renderer, LINEJOIN_MITER);
-  DIA_RENDERER_GET_CLASS (renderer)->set_linecaps(renderer, LINECAPS_ROUND);
-
-  /* the cairo text path is position independent, Dia's bezier are not */
-  x = obj->position.x;
-  y = obj->position.y;
-
-  /* count Dia BezPoints required */
-  total = 0;
-  for (i=0; i < outline->path->num_data; i += outline->path->data[i].header.length) {
-    ++total;
-  }
-
-  pts = g_alloca (sizeof(BezPoint)*(total));
-  for (i=0; i < outline->path->num_data; i += outline->path->data[i].header.length) {
-    cairo_path_data_t *data = &outline->path->data[i];
-    if (CAIRO_PATH_MOVE_TO == data->header.type) {
-      /* Dia can't handle moveto except at start: corrected below */
-      pts[n].type = BEZ_MOVE_TO;
-      ps.x = pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y * outline->mat.xy + x;
-      ps.y = pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y * outline->mat.yy + y;
-      ++n;
-    } else if (CAIRO_PATH_LINE_TO == data->header.type) {
-      pts[n].type = BEZ_LINE_TO;
-      pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y *  outline->mat.xy + x;
-      pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y *  outline->mat.yy + y;
-      ++n;
-    } else if (CAIRO_PATH_CURVE_TO == data->header.type) {
-      pts[n].type = BEZ_CURVE_TO;
-      pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y *  outline->mat.xy + x;
-      pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y *  outline->mat.yy + y;
-      pts[n].p2.x = data[2].point.x * outline->mat.xx + data[2].point.y *  outline->mat.xy + x;
-      pts[n].p2.y = data[2].point.x * outline->mat.yx + data[2].point.y *  outline->mat.yy + y;
-      pts[n].p3.x = data[3].point.x * outline->mat.xx + data[3].point.y *  outline->mat.xy + x;
-      pts[n].p3.y = data[3].point.x * outline->mat.yx + data[3].point.y *  outline->mat.yy + y;
-      ++n;
-    } else if (CAIRO_PATH_CLOSE_PATH == data->header.type) {
-      pts[n].type = BEZ_LINE_TO;
-      pts[n].p1.x = ps.x;
-      pts[n].p1.y = ps.y;
-      ++n;
-    }
-  }
-  /* split the path data into piece which can be handled by Dia's bezier rendering */
-  if (outline->show_background) {
-    /* first draw the fills */
-    int s1 = 0, n1 = 0;
-    int s2 = 0;
-    for (i = 1; i < total; ++i) {
-      if (BEZ_MOVE_TO == pts[i].type) {
-        /* check wether any point of the second outline is within the first outline. 
-	 * If so it need to be subtracted - currently blanked. */
-	real dist = distance_bez_shape_point (&pts[s1], 
-	  n1 > 0 ? n1 : i - s1 - 1, 0, &pts[i].p1);
-	if (s2 > s1) { /* blanking the previous one */
-	  n = i - s2 - 1;
-          DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s2], n, &color_white);
-	} else { /* fill the outer shape */
-	  n1 = n = i - s1 - 1;
-          DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s1], n, &outline->fill_color);
-	}
-	if (dist > 0) { /* remember as new outer outline */
-	  s1 = i;
-	  n1 = 0;
-	  s2 = 0;
-	} else {
-	  s2 = i;
-	}
-      }
-    }
-    /* the last one is not drawn yet */
-    if (s2 > s1) { /* blanking the previous one */
-      if (s2 - i - 1 > 1) /* depending on the above we may be ready */
-        DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s2], s2 - i - 1, &color_white);
-    } else {
-      if (s1 - i - 1 > 1)
-        DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s1], s1 - i - 1, &outline->fill_color);
-    }
-  } /* show_background */
-  n = 0;
-  for (i = 1; i < total; ++i) {
-    if (BEZ_MOVE_TO == pts[i].type) {
-      DIA_RENDERER_GET_CLASS (renderer)->draw_bezier (renderer, &pts[n], i - n, &outline->line_color);
-      n = i;
-    }
-  }
-  /* the last one, if there is one */
-  if (i - n - 1 > 0)
+}
+static void 
+outline_draw(Outline *outline, DiaRenderer *renderer)
+{
+  DiaObject *obj = &outline->object;
+  int i, n = 0, total;
+  BezPoint *pts;
+  real x, y;
+  Point ps = {0, 0}; /* silence gcc */
+  
+  if (!outline->path)
+    return;
+  DIA_RENDERER_GET_CLASS (renderer)->set_linewidth (renderer, outline->line_width);
+  DIA_RENDERER_GET_CLASS (renderer)->set_linestyle (renderer, LINESTYLE_SOLID);
+  DIA_RENDERER_GET_CLASS (renderer)->set_linejoin(renderer, LINEJOIN_MITER);
+  DIA_RENDERER_GET_CLASS (renderer)->set_linecaps(renderer, LINECAPS_ROUND);
+
+  /* the cairo text path is position independent, Dia's bezier are not */
+  x = obj->position.x;
+  y = obj->position.y;
+
+  /* count Dia BezPoints required */
+  total = 0;
+  for (i=0; i < outline->path->num_data; i += outline->path->data[i].header.length) {
+    ++total;
+  }
+
+  pts = g_alloca (sizeof(BezPoint)*(total));
+  for (i=0; i < outline->path->num_data; i += outline->path->data[i].header.length) {
+    cairo_path_data_t *data = &outline->path->data[i];
+    if (CAIRO_PATH_MOVE_TO == data->header.type) {
+      /* Dia can't handle moveto except at start: corrected below */
+      pts[n].type = BEZ_MOVE_TO;
+      ps.x = pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y * outline->mat.xy + x;
+      ps.y = pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y * outline->mat.yy + y;
+      ++n;
+    } else if (CAIRO_PATH_LINE_TO == data->header.type) {
+      pts[n].type = BEZ_LINE_TO;
+      pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y *  outline->mat.xy + x;
+      pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y *  outline->mat.yy + y;
+      ++n;
+    } else if (CAIRO_PATH_CURVE_TO == data->header.type) {
+      pts[n].type = BEZ_CURVE_TO;
+      pts[n].p1.x = data[1].point.x * outline->mat.xx + data[1].point.y *  outline->mat.xy + x;
+      pts[n].p1.y = data[1].point.x * outline->mat.yx + data[1].point.y *  outline->mat.yy + y;
+      pts[n].p2.x = data[2].point.x * outline->mat.xx + data[2].point.y *  outline->mat.xy + x;
+      pts[n].p2.y = data[2].point.x * outline->mat.yx + data[2].point.y *  outline->mat.yy + y;
+      pts[n].p3.x = data[3].point.x * outline->mat.xx + data[3].point.y *  outline->mat.xy + x;
+      pts[n].p3.y = data[3].point.x * outline->mat.yx + data[3].point.y *  outline->mat.yy + y;
+      ++n;
+    } else if (CAIRO_PATH_CLOSE_PATH == data->header.type) {
+      pts[n].type = BEZ_LINE_TO;
+      pts[n].p1.x = ps.x;
+      pts[n].p1.y = ps.y;
+      ++n;
+    }
+  }
+
+  if (DIA_RENDERER_GET_CLASS (renderer)->is_capable_to(renderer, RENDER_HOLES)) {
+    if (outline->show_background)
+      DIA_RENDERER_GET_CLASS (renderer)->fill_bezier(renderer, pts, total, &outline->fill_color);
+    DIA_RENDERER_GET_CLASS (renderer)->draw_bezier (renderer, pts, total, &outline->line_color);
+    return; /* that was easy ;) */
+  }
+  /* otherwise split the path data into piece which can be handled by Dia's standard bezier rendering */
+  if (outline->show_background) {
+    /* first draw the fills */
+    int s1 = 0, n1 = 0;
+    int s2 = 0;
+    for (i = 1; i < total; ++i) {
+      if (BEZ_MOVE_TO == pts[i].type) {
+        /* check wether any point of the second outline is within the first outline. 
+	 * If so it need to be subtracted - currently blanked. */
+	real dist = distance_bez_shape_point (&pts[s1], 
+	  n1 > 0 ? n1 : i - s1 - 1, 0, &pts[i].p1);
+	if (s2 > s1) { /* blanking the previous one */
+	  n = i - s2 - 1;
+          DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s2], n, &color_white);
+	} else { /* fill the outer shape */
+	  n1 = n = i - s1 - 1;
+          DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s1], n, &outline->fill_color);
+	}
+	if (dist > 0) { /* remember as new outer outline */
+	  s1 = i;
+	  n1 = 0;
+	  s2 = 0;
+	} else {
+	  s2 = i;
+	}
+      }
+    }
+    /* the last one is not drawn yet */
+    if (s2 > s1) { /* blanking the previous one */
+      if (s2 - i - 1 > 1) /* depending on the above we may be ready */
+        DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s2], s2 - i - 1, &color_white);
+    } else {
+      if (s1 - i - 1 > 1)
+        DIA_RENDERER_GET_CLASS (renderer)->fill_bezier (renderer, &pts[s1], s1 - i - 1, &outline->fill_color);
+    }
+  } /* show_background */
+  n = 0;
+  for (i = 1; i < total; ++i) {
+    if (BEZ_MOVE_TO == pts[i].type) {
+      DIA_RENDERER_GET_CLASS (renderer)->draw_bezier (renderer, &pts[n], i - n, &outline->line_color);
+      n = i;
+    }
+  }
+  /* the last one, if there is one */
+  if (i - n - 1 > 0)
     DIA_RENDERER_GET_CLASS (renderer)->draw_bezier (renderer, &pts[n], i - n - 1, &outline->line_color);
-}
-/* returning used to crash Dia, the method needed to be NULL if there is nothing to do */
-static DiaMenu *
-outline_get_object_menu(Outline *outline, Point *clickedpoint)
-{
-  return NULL;
-}
-
-/*! A standard props compliant object needs to describe its parameters */
-static PropDescription *
-outline_describe_props (Outline *outline)
-{
-  if (outline_props[0].quark == 0)
-    prop_desc_list_calculate_quarks(outline_props);
-  return outline_props;
-}
-static void 
-outline_get_props (Outline *outline, GPtrArray *props)
-{
-  object_get_props_from_offsets(&outline->object, outline_offsets, props);
-}
-static void 
-outline_set_props (Outline *outline, GPtrArray *props)
-{
-  object_set_props_from_offsets(&outline->object, outline_offsets, props);
-  outline_update_data (outline);
-}
-static real
-outline_distance_from (Outline *outline, Point *point)
-{
-  return distance_polygon_point (&outline->ink_rect[0], 4, outline->line_width, point);
-}
-static ObjectChange* 
-outline_move_handle (Outline *outline,
-                     Handle *handle,
-		     Point *to, ConnectionPoint *cp,
-		     HandleMoveReason reason, ModifierKeys modifiers)
-{
-  DiaObject *obj = &outline->object;
-  Point start = obj->position;
-  Point end = outline->ink_rect[2];
-  real dist, old_dist = distance_point_point (&start, &end);
-  Point norm = end;
-  point_sub (&norm, &start);
-  point_normalize (&norm);
-  /* we use this to modify angle and scale */
-  switch (handle->id) {
-  case HANDLE_RESIZE_NW :
-    start = *to;
-    break;
-  case HANDLE_RESIZE_SE :
-    end = *to;
-    break;
-  default :
-    g_warning ("Outline unknown handle");
-  }
-  dist = distance_point_point (&start, &end);
-  /* disallow everything below a certain level, otherwise the font-size could become invalid */
-  if (dist > 0.1) {
-    obj->position = start;
-    
-    outline->font_height *= (dist / old_dist);
-  
-    outline_update_data (outline);
-  }
-  return NULL;
-}
-static ObjectChange* 
-outline_move (Outline *outline, Point *to)
-{
-  DiaObject *obj = &outline->object;
-
-  obj->position = *to;
-
-  outline_update_data (outline);
-  return NULL;
-}
-static DiaObject *
-outline_copy (Outline *from)
-{
-  Outline *to;
-  
-  to = g_new0 (Outline, 1);
-  object_copy (&from->object, &to->object);
-  outline_init_handles (to);
-  to->name = g_strdup (from->name);
-  to->rotation = from->rotation;
-  to->font = dia_font_copy (from->font);
-  to->font_height = from->font_height;
-  to->line_width = from->line_width;
-  to->line_color = from->line_color;
-  to->fill_color = from->fill_color;
-  to->show_background = from->show_background;
-  /* the rest will be recalculated in update_data() */
-  outline_update_data (to);
-
-  return &to->object;
-}
-static void 
-outline_destroy (Outline *outline)
-{
-  if (outline->path)
+}
+/* returning used to crash Dia, the method needed to be NULL if there is nothing to do */
+static DiaMenu *
+outline_get_object_menu(Outline *outline, Point *clickedpoint)
+{
+  return NULL;
+}
+
+/*! A standard props compliant object needs to describe its parameters */
+static PropDescription *
+outline_describe_props (Outline *outline)
+{
+  if (outline_props[0].quark == 0)
+    prop_desc_list_calculate_quarks(outline_props);
+  return outline_props;
+}
+static void 
+outline_get_props (Outline *outline, GPtrArray *props)
+{
+  object_get_props_from_offsets(&outline->object, outline_offsets, props);
+}
+static void 
+outline_set_props (Outline *outline, GPtrArray *props)
+{
+  object_set_props_from_offsets(&outline->object, outline_offsets, props);
+  outline_update_data (outline);
+}
+static real
+outline_distance_from (Outline *outline, Point *point)
+{
+  return distance_polygon_point (&outline->ink_rect[0], 4, outline->line_width, point);
+}
+static ObjectChange* 
+outline_move_handle (Outline *outline,
+                     Handle *handle,
+		     Point *to, ConnectionPoint *cp,
+		     HandleMoveReason reason, ModifierKeys modifiers)
+{
+  DiaObject *obj = &outline->object;
+  Point start = obj->position;
+  Point end = outline->ink_rect[2];
+  real dist, old_dist = distance_point_point (&start, &end);
+  Point norm = end;
+  point_sub (&norm, &start);
+  point_normalize (&norm);
+  /* we use this to modify angle and scale */
+  switch (handle->id) {
+  case HANDLE_RESIZE_NW :
+    start = *to;
+    break;
+  case HANDLE_RESIZE_SE :
+    end = *to;
+    break;
+  default :
+    g_warning ("Outline unknown handle");
+  }
+  dist = distance_point_point (&start, &end);
+  /* disallow everything below a certain level, otherwise the font-size could become invalid */
+  if (dist > 0.1) {
+    obj->position = start;
+    
+    outline->font_height *= (dist / old_dist);
+  
+    outline_update_data (outline);
+  }
+  return NULL;
+}
+static ObjectChange* 
+outline_move (Outline *outline, Point *to)
+{
+  DiaObject *obj = &outline->object;
+
+  obj->position = *to;
+
+  outline_update_data (outline);
+  return NULL;
+}
+static DiaObject *
+outline_copy (Outline *from)
+{
+  Outline *to;
+  
+  to = g_new0 (Outline, 1);
+  object_copy (&from->object, &to->object);
+  outline_init_handles (to);
+  to->name = g_strdup (from->name);
+  to->rotation = from->rotation;
+  to->font = dia_font_copy (from->font);
+  to->font_height = from->font_height;
+  to->line_width = from->line_width;
+  to->line_color = from->line_color;
+  to->fill_color = from->fill_color;
+  to->show_background = from->show_background;
+  /* the rest will be recalculated in update_data() */
+  outline_update_data (to);
+
+  return &to->object;
+}
+static void 
+outline_destroy (Outline *outline)
+{
+  if (outline->path)
     cairo_path_destroy (outline->path);
-  g_free (outline->name);
-  object_destroy(&outline->object);
-  /* but not the object itself? */
-}
-static void 
-outline_select (Outline *outline, Point *clicked_point,
-		DiaRenderer *interactive_renderer)
-{
-  outine_update_handles (outline);
-}
-#endif /* HAVE_CAIRO */
+  g_free (outline->name);
+  object_destroy(&outline->object);
+  /* but not the object itself? */
+}
+static void 
+outline_select (Outline *outline, Point *clicked_point,
+		DiaRenderer *interactive_renderer)
+{
+  outine_update_handles (outline);
+}
+
+#endif /* HAVE_CAIRO */
 
diff --git a/plug-ins/cairo/diacairo-renderer.c b/plug-ins/cairo/diacairo-renderer.c
index 1ab5cbf..4110a9b 100644
--- a/plug-ins/cairo/diacairo-renderer.c
+++ b/plug-ins/cairo/diacairo-renderer.c
@@ -160,6 +160,16 @@ end_render(DiaRenderer *self)
   DIAG_STATE(renderer->cr)
 }
 
+static gboolean 
+is_capable_to (DiaRenderer *renderer, RenderCapability cap)
+{
+  if (RENDER_HOLES == cap)
+    return TRUE;
+  else if (RENDER_ALPHA == cap)
+    return TRUE;
+  return FALSE;
+}
+
 static void
 set_linewidth(DiaRenderer *self, real linewidth)
 {  
@@ -1014,4 +1024,7 @@ cairo_renderer_class_init (DiaCairoRendererClass *klass)
   /* highest level functions */
   renderer_class->draw_rounded_rect = draw_rounded_rect;
   renderer_class->fill_rounded_rect = fill_rounded_rect;
+  
+  /* other */
+  renderer_class->is_capable_to = is_capable_to;
 }
diff --git a/plug-ins/libart/dialibartrenderer.c b/plug-ins/libart/dialibartrenderer.c
index 5f12d46..7a6bc08 100644
--- a/plug-ins/libart/dialibartrenderer.c
+++ b/plug-ins/libart/dialibartrenderer.c
@@ -139,7 +139,15 @@ end_render(DiaRenderer *self)
   dia_font_pop_context();
 }
 
-
+static gboolean 
+is_capable_to (DiaRenderer *renderer, RenderCapability cap)
+{
+  if (RENDER_HOLES == cap)
+    return TRUE;
+  else if (RENDER_ALPHA == cap)
+    return TRUE;
+  return FALSE;
+}
 
 static void
 set_linewidth(DiaRenderer *self, real linewidth)
@@ -1512,6 +1520,8 @@ dia_libart_renderer_class_init (DiaLibartRendererClass *klass)
 
   /* Interactive functions */
   renderer_class->get_text_width = get_text_width;
+  /* other */
+  renderer_class->is_capable_to = is_capable_to;
 }
 
 #endif
diff --git a/plug-ins/wmf/wmf.cpp b/plug-ins/wmf/wmf.cpp
index d0ebccb..e07cdbe 100644
--- a/plug-ins/wmf/wmf.cpp
+++ b/plug-ins/wmf/wmf.cpp
@@ -37,7 +37,6 @@ extern "C" {
 #include "filter.h"
 #include "plug-ins.h"
 #include "dia_image.h"
-
 #ifdef __cplusplus
 }
 #endif
@@ -326,6 +325,16 @@ end_render(DiaRenderer *self)
         g_object_unref (renderer->pango_context);
 }
 
+static gboolean 
+is_capable_to (DiaRenderer *renderer, RenderCapability cap)
+{
+  if (RENDER_HOLES == cap)
+    return TRUE;
+  else if (RENDER_ALPHA == cap)
+    return TRUE;
+  return FALSE;
+}
+
 static void
 set_linewidth(DiaRenderer *self, real linewidth)
 {  
@@ -815,11 +824,70 @@ fill_ellipse(DiaRenderer *self,
 }
 
 static void
+_bezier (DiaRenderer *self, 
+	    BezPoint *points,
+	    int       numpoints,
+	    Color    *colour,
+	    gboolean  fill)
+{
+    WmfRenderer *renderer = WMF_RENDERER (self);
+    W32::HGDIOBJ hBrush, hBrOld;
+    W32::HPEN hPen;
+    W32::COLORREF rgb = W32COLOR(colour);
+
+    DIAG_NOTE(renderer, "_bezier n:%d %fx%f ...\n", 
+              numpoints, points->p1.x, points->p1.y);
+
+    if (fill) {
+      hBrush = W32::CreateSolidBrush(rgb);
+      hBrOld = W32::SelectObject(renderer->hFileDC, hBrush);
+    } else {
+      hPen = UsePen(renderer, colour);
+    }
+
+    W32::BeginPath (renderer->hFileDC);
+    
+    for (int i = 0; i < numpoints; ++i) {
+        switch (points[i].type) {
+	case BezPoint::BEZ_MOVE_TO :
+	    W32::MoveToEx (renderer->hFileDC, SCX(points[i].p1.x), SCX(points[i].p1.y), NULL);
+	    break;
+	case BezPoint::BEZ_LINE_TO :
+	    W32::LineTo (renderer->hFileDC, SCX(points[i].p1.x), SCX(points[i].p1.y));
+	    break;
+	case BezPoint::BEZ_CURVE_TO :
+	  {
+	    W32::POINT pts[3] = {
+	      {SCX(points[i].p1.x), SCX(points[i].p1.y)},
+	      {SCX(points[i].p2.x), SCX(points[i].p2.y)},
+	      {SCX(points[i].p3.x), SCX(points[i].p3.y)}
+	    };
+	    W32::PolyBezierTo (renderer->hFileDC, pts, 3);
+	  }
+	  break;
+	}
+    }
+    W32::EndPath (renderer->hFileDC);
+    if (fill) {
+        W32::FillPath (renderer->hFileDC);
+        W32::SelectObject(renderer->hFileDC, 
+                          W32::GetStockObject (HOLLOW_BRUSH) );
+        W32::DeleteObject(hBrush);
+    } else {
+        W32::StrokePath (renderer->hFileDC);
+        DonePen(renderer, hPen);
+    }
+}
+
+static void
 draw_bezier(DiaRenderer *self, 
 	    BezPoint *points,
 	    int numpoints,
 	    Color *colour)
 {
+#ifndef SAVE_EMF
+    _bezier(self, points, numpoints, colour, FALSE);
+#else
     WmfRenderer *renderer = WMF_RENDERER (self);
     W32::HPEN    hPen;
     W32::POINT * pts;
@@ -839,14 +907,14 @@ draw_bezier(DiaRenderer *self,
         {
         case _BezPoint::BEZ_MOVE_TO:
             g_warning("only first BezPoint can be a BEZ_MOVE_TO");
-	      break;
+	  break;
         case _BezPoint::BEZ_LINE_TO:
             /* everyhing the same ?*/
             pts[i*3-2].x = pts[i*3-1].x = 
             pts[i*3  ].x = SCX(points[i].p1.x);
             pts[i*3-2].y = pts[i*3-1].y = 
             pts[i*3  ].y = SCY(points[i].p1.y);
-        break;
+          break;
         case _BezPoint::BEZ_CURVE_TO:
             /* control points */
             pts[i*3-2].x = SCX(points[i].p1.x);
@@ -870,6 +938,7 @@ draw_bezier(DiaRenderer *self,
     DonePen(renderer, hPen);
 
     g_free(pts);
+#endif
 }
 
 #ifndef SAVE_EMF
@@ -880,24 +949,7 @@ fill_bezier(DiaRenderer *self,
 	    int numpoints,
 	    Color *colour)
 {
-    WmfRenderer *renderer = WMF_RENDERER (self);
-    W32::HGDIOBJ hBrush, hBrOld;
-    W32::COLORREF rgb = W32COLOR(colour);
-
-    DIAG_NOTE(renderer, "fill_bezier n:%d %fx%f ...\n", 
-              numpoints, points->p1.x, points->p1.y);
-
-    hBrush = W32::CreateSolidBrush(rgb);
-    hBrOld = W32::SelectObject(renderer->hFileDC, hBrush);
-
-    W32::BeginPath (renderer->hFileDC);
-    draw_bezier(self, points, numpoints, NULL);
-    W32::EndPath (renderer->hFileDC);
-    W32::FillPath (renderer->hFileDC);
-
-    W32::SelectObject(renderer->hFileDC, 
-                      W32::GetStockObject (HOLLOW_BRUSH) );
-    W32::DeleteObject(hBrush);
+    _bezier(self, points, numpoints, colour, TRUE);
 }
 #endif
 
@@ -1210,6 +1262,8 @@ wmf_renderer_class_init (WmfRendererClass *klass)
   renderer_class->draw_rounded_rect = draw_rounded_rect;
   renderer_class->fill_rounded_rect = fill_rounded_rect;
 #endif
+  /* other */
+  renderer_class->is_capable_to = is_capable_to;
 }
 
 /* plug-in export api */



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