[goffice] Make GocGroup usable as a widgetless canvas.



commit 0caf4bd4b373e897d647a3475b4d37f5a41620ea
Author: Jean Brefort <jean brefort normalesup org>
Date:   Mon Jun 22 13:21:54 2020 +0200

    Make GocGroup usable as a widgetless canvas.

 ChangeLog                        |   8 ++
 NEWS                             |   1 +
 goffice/canvas/goc-arc.c         |  27 ++++-
 goffice/canvas/goc-circle.c      |  15 +++
 goffice/canvas/goc-component.c   |   4 +-
 goffice/canvas/goc-ellipse.c     |  19 +++-
 goffice/canvas/goc-graph.c       |   2 +-
 goffice/canvas/goc-group.c       |  28 ++++-
 goffice/canvas/goc-image.c       |  21 +++-
 goffice/canvas/goc-item.c        |  59 +++++++++-
 goffice/canvas/goc-item.h        |   6 +-
 goffice/canvas/goc-line.c        |  20 +++-
 goffice/canvas/goc-path.c        |  17 ++-
 goffice/canvas/goc-pixbuf.c      |   2 +-
 goffice/canvas/goc-polygon.c     |  29 ++++-
 goffice/canvas/goc-polyline.c    |  22 +++-
 goffice/canvas/goc-rectangle.c   |  22 +++-
 goffice/canvas/goc-styled-item.c |  13 ++-
 goffice/canvas/goc-text.c        |  29 ++++-
 goffice/utils/go-emf.c           | 236 ++++++++++++++++++++-------------------
 goffice/utils/go-image.c         |  12 +-
 tests/mf-demo.c                  |   1 +
 22 files changed, 439 insertions(+), 154 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 77355b67..7bcc4048 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2020-06-22  Jean Brefort  <jean brefort normalesup org>
+
+       * goffice/canvas/*: enable GocGroup to work as a widgtless canvas.
+       * goffice/utils/go-emf.c: replace the canvas by a GocGroup.
+       * goffice/utils/go-image.c (go_image_new_from_data),
+       (go_image_type_for_format): ditto.
+       * tests/mf-demo.c (open_file): ditto.
+
 2020-06-15  Jean Brefort  <jean brefort normalesup org>
 
        * goffice/utils/go-emf.c (go_emf_bitblt): implement filling with a solid
diff --git a/NEWS b/NEWS
index 2ce57280..654034b6 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Jean:
        * Optimize GtkWidget embedding in the canvas. See #465.
        * Clip grid lines rendering to the plot area. [#50]
        * Speed up GocGroup for large number of children.  [Gnumeric #465]
+       * Make GocGroup usable as a widgetless canvas.
 
 Morten:
        * Avoid critical in document image handling.
diff --git a/goffice/canvas/goc-arc.c b/goffice/canvas/goc-arc.c
index 56e544ad..6e2cda34 100644
--- a/goffice/canvas/goc-arc.c
+++ b/goffice/canvas/goc-arc.c
@@ -33,6 +33,8 @@
  * arrows at the start and/or at the end.
 **/
 
+static GocItemClass *parent_class;
+
 enum {
        ARC_PROP_0,
        ARC_PROP_XC,
@@ -163,7 +165,7 @@ goc_arc_start (GocItem const *item, double *x, double *y, double *phi)
 {
        GocArc *arc = GOC_ARC (item);
        double x1, y1, s;
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
 
        x1 = arc->xr * cos (atan2 (arc->xr / arc->yr * sin (arc->ang1), cos (arc->ang1)));
        y1 = arc->yr * sin (atan2 (arc->xr / arc->yr * sin (arc->ang1), cos (arc->ang1)));
@@ -182,7 +184,7 @@ goc_arc_end (GocItem const *item, double *x, double *y, double *phi)
 {
        GocArc *arc = GOC_ARC (item);
        double x1, y1, s;
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
 
        x1 = arc->xr * cos (atan2 (arc->xr / arc->yr * sin (arc->ang2), cos (arc->ang2)));
        y1 = arc->yr * sin (atan2 (arc->xr / arc->yr * sin (arc->ang2), cos (arc->ang2)));
@@ -203,7 +205,7 @@ prepare_draw_arrow (GocItem const *item, cairo_t *cr, gboolean end, gboolean fla
        GocArc *arc = GOC_ARC (item);
        GOArrow const *arrow;
        GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
        double rsign = sign;
 
        w = style->line.width? style->line.width / 2.0: 0.5;
@@ -409,6 +411,23 @@ goc_arc_draw (GocItem const *item, cairo_t *cr)
        cairo_restore(cr);
 }
 
+static void
+goc_arc_copy (GocItem *dest, GocItem *source)
+{
+       GocArc *src = GOC_ARC (source), *dst = GOC_ARC (dest);
+
+       dst->xc = src->xc;
+       dst->yc = src->yc;
+       dst->xr = src->xr;
+       dst->yr = src->yr;
+       dst->ang1 = src->ang1;
+       dst->ang2 = src->ang2;
+       dst->type = src->type;
+       dst->start_arrow = src->start_arrow;
+       dst->end_arrow = src->end_arrow;
+       parent_class->copy (dest, source);
+}
+
 static void
 goc_arc_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -436,6 +455,7 @@ goc_arc_class_init (GocItemClass *item_klass)
 {
        GObjectClass *obj_klass = (GObjectClass *) item_klass;
        GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+       parent_class = g_type_class_peek_parent (item_klass);
 
        gsi_klass->init_style = goc_arc_init_style;
 
@@ -506,6 +526,7 @@ goc_arc_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_arc_update_bounds;
        item_klass->distance = goc_arc_distance;
        item_klass->draw = goc_arc_draw;
+       item_klass->copy = goc_arc_copy;
 }
 
 GSF_CLASS (GocArc, goc_arc,
diff --git a/goffice/canvas/goc-circle.c b/goffice/canvas/goc-circle.c
index b32fe690..6966b3f9 100644
--- a/goffice/canvas/goc-circle.c
+++ b/goffice/canvas/goc-circle.c
@@ -33,6 +33,8 @@
  * #GocCircle implements circle drawing in the canvas.
 **/
 
+static GocItemClass *parent_class;
+
 enum {
        CIRCLE_PROP_0,
        CIRCLE_PROP_X,
@@ -145,6 +147,17 @@ goc_circle_update_bounds (GocItem *item)
        item->y1 = circle->y + r;
 }
 
+static void
+goc_circle_copy (GocItem *dest, GocItem *source)
+{
+       GocCircle *src = GOC_CIRCLE (source), *dst = GOC_CIRCLE (dest);
+
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->radius = src->radius;
+       parent_class->copy (dest, source);
+}
+
 static void
 goc_circle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -166,6 +179,7 @@ goc_circle_class_init (GocItemClass *item_klass)
 {
        GObjectClass *obj_klass = (GObjectClass *) item_klass;
        GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+       parent_class = g_type_class_peek_parent (item_klass);
 
        obj_klass->get_property = goc_circle_get_property;
        obj_klass->set_property = goc_circle_set_property;
@@ -192,6 +206,7 @@ goc_circle_class_init (GocItemClass *item_klass)
 
        item_klass->distance = goc_circle_distance;
        item_klass->draw = goc_circle_draw;
+       item_klass->copy = goc_circle_copy;
        item_klass->update_bounds = goc_circle_update_bounds;
 }
 
diff --git a/goffice/canvas/goc-component.c b/goffice/canvas/goc-component.c
index 9179642c..8b88ab86 100644
--- a/goffice/canvas/goc-component.c
+++ b/goffice/canvas/goc-component.c
@@ -207,7 +207,7 @@ goc_component_draw (GocItem const *item, cairo_t *cr)
        GocComponent *component = GOC_COMPONENT (item);
        GocCanvas *canvas = item->canvas;
        double x0, y0 = component->y;
-       if (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
+       if (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
                x0 = component->x + component->w;
                goc_group_adjust_coords (item->parent, &x0, &y0);
                x0 = canvas->width - (int) (x0 - canvas->scroll_x1);
@@ -245,7 +245,7 @@ goc_component_update_bounds (GocItem *item)
        double x0, y0 = component->y;
        GocCanvas *canvas = item->canvas;
 
-       if (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
+       if (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
                x0 = component->x + component->w;
                goc_group_adjust_coords (item->parent, &x0, &y0);
                x0 = canvas->width - (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
diff --git a/goffice/canvas/goc-ellipse.c b/goffice/canvas/goc-ellipse.c
index 49a2037f..d38a7b4d 100644
--- a/goffice/canvas/goc-ellipse.c
+++ b/goffice/canvas/goc-ellipse.c
@@ -32,6 +32,8 @@
  * #GocEllipse implements ellipse drawing in the canvas.
 **/
 
+static GocItemClass *parent_class;
+
 enum {
        ELLIPSE_PROP_0,
        ELLIPSE_PROP_X,
@@ -110,7 +112,7 @@ static gboolean
 goc_ellipse_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
 {
        GocEllipse *ellipse = GOC_ELLIPSE (item);
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
 
        if (0 == ellipse->width && 0 == ellipse->height)
                return FALSE;
@@ -234,6 +236,19 @@ goc_ellipse_draw (GocItem const *item, cairo_t *cr)
                cairo_restore(cr);
 }
 
+static void
+goc_ellipse_copy (GocItem *dest, GocItem *source)
+{
+       GocEllipse *src = GOC_ELLIPSE (source), *dst = GOC_ELLIPSE (dest);
+
+       dst->rotation = src->rotation;
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->width = src->width;
+       dst->height = src->height;
+       parent_class->copy (dest, source);
+}
+
 static void
 goc_ellipse_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -255,6 +270,7 @@ goc_ellipse_class_init (GocItemClass *item_klass)
 {
        GObjectClass *obj_klass = (GObjectClass *) item_klass;
        GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+       parent_class = g_type_class_peek_parent (item_klass);
 
        obj_klass->get_property = goc_ellipse_get_property;
        obj_klass->set_property = goc_ellipse_set_property;
@@ -294,6 +310,7 @@ goc_ellipse_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_ellipse_update_bounds;
        item_klass->distance = goc_ellipse_distance;
        item_klass->draw = goc_ellipse_draw;
+       item_klass->copy = goc_ellipse_copy;
 }
 
 GSF_CLASS (GocEllipse, goc_ellipse,
diff --git a/goffice/canvas/goc-graph.c b/goffice/canvas/goc-graph.c
index 807a5d0c..ccc90641 100644
--- a/goffice/canvas/goc-graph.c
+++ b/goffice/canvas/goc-graph.c
@@ -189,7 +189,7 @@ goc_graph_draw (GocItem const *item, cairo_t *cr)
        double x0, y0 = item->y0;
        if (graph->renderer == NULL)
                return;
-       if (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
+       if (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL) {
                x0 = item->x1;
                goc_group_adjust_coords (item->parent, &x0, &y0);
                x0 = canvas->width - (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
diff --git a/goffice/canvas/goc-group.c b/goffice/canvas/goc-group.c
index 0e9ae68b..8ac0b08f 100644
--- a/goffice/canvas/goc-group.c
+++ b/goffice/canvas/goc-group.c
@@ -263,6 +263,22 @@ goc_group_finalize (GObject *obj)
        ((GObjectClass*)parent_klass)->finalize (obj);
 }
 
+static void
+goc_group_copy (GocItem *dest, GocItem *source)
+{
+       GocGroup *src = GOC_GROUP (source), *dst = GOC_GROUP (dest);
+       unsigned ui;
+
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->clip_path = go_path_copy (src->clip_path);
+       dst->clip_rule = src->clip_rule;
+       goc_group_freeze (dst, TRUE);
+       for (ui = 0; ui < src->priv->children->len; ui++)
+               goc_item_duplicate (g_ptr_array_index (src->priv->children, ui), dst);
+       goc_group_freeze (dst, FALSE);
+}
+
 static void
 goc_group_class_init (GocItemClass *item_klass)
 {
@@ -292,6 +308,7 @@ goc_group_class_init (GocItemClass *item_klass)
        item_klass->realize = goc_group_realize;
        item_klass->unrealize = goc_group_unrealize;
        item_klass->notify_scrolled = goc_group_notify_scrolled;
+       item_klass->copy = goc_group_copy;
 }
 
 static void
@@ -590,10 +607,13 @@ goc_group_cairo_transform (GocGroup const *group, cairo_t *cr, double x, double
                goc_group_cairo_transform (parent, cr, x + group->x, y + group->y);
        else {
                GocCanvas *canvas = GOC_ITEM (group)->canvas;
-               if (canvas->direction == GOC_DIRECTION_RTL)
-                       cairo_translate (cr, canvas->width / canvas->pixels_per_unit - (x - 
canvas->scroll_x1), y - canvas->scroll_y1);
-               else
-                       cairo_translate (cr, x - canvas->scroll_x1, y - canvas->scroll_y1);
+               if (canvas) {
+                       if (canvas->direction == GOC_DIRECTION_RTL)
+                               cairo_translate (cr, canvas->width / canvas->pixels_per_unit - (x - 
canvas->scroll_x1), y - canvas->scroll_y1);
+                       else
+                               cairo_translate (cr, x - canvas->scroll_x1, y - canvas->scroll_y1);
+               } else
+                       cairo_translate (cr, x, y);
        }
 }
 
diff --git a/goffice/canvas/goc-image.c b/goffice/canvas/goc-image.c
index 8c0c8802..56261b35 100644
--- a/goffice/canvas/goc-image.c
+++ b/goffice/canvas/goc-image.c
@@ -241,7 +241,7 @@ goc_image_draw (GocItem const *item, cairo_t *cr)
 
        cairo_save (cr);
        _goc_item_transform (item, cr, TRUE);
-       x = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)?
+       x = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)?
                image->x + image->width: image->x;
        goc_group_cairo_transform (item->parent, cr, x, (int) image->y);
        cairo_rotate (cr, image->rotation);
@@ -256,6 +256,24 @@ goc_image_draw (GocItem const *item, cairo_t *cr)
        cairo_restore (cr);
 }
 
+static void
+goc_image_copy (GocItem *dest, GocItem *source)
+{
+       GocImage *src = GOC_IMAGE (source), *dst = GOC_IMAGE (dest);
+
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->width = src->width;
+       dst->height = src->height;
+       dst->rotation = src->rotation;
+       dst->crop_left = src->crop_left;
+       dst->crop_right = src->crop_right;
+       dst->crop_top = src->crop_top;
+       dst->crop_bottom = src->crop_bottom;
+       /* just add a reference to the GOImage, it should never be modified */
+       dst->image = g_object_ref (src->image);
+}
+
 static void
 goc_image_class_init (GocItemClass *item_klass)
 {
@@ -324,6 +342,7 @@ goc_image_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_image_update_bounds;
        item_klass->distance = goc_image_distance;
        item_klass->draw = goc_image_draw;
+       item_klass->copy = goc_image_copy;
 }
 
 GSF_CLASS (GocImage, goc_image,
diff --git a/goffice/canvas/goc-item.c b/goffice/canvas/goc-item.c
index 090dc337..33b02896 100644
--- a/goffice/canvas/goc-item.c
+++ b/goffice/canvas/goc-item.c
@@ -470,7 +470,7 @@ goc_item_maybe_invalidate (GocItem *item, gboolean ignore_visibility)
        if (!parent)
                return;
 
-       if (!goc_canvas_get_realized (item->canvas))
+       if (!item->canvas || !goc_canvas_get_realized (item->canvas))
                return;
 
        if (!ignore_visibility && !item->visible)
@@ -825,8 +825,9 @@ goc_item_set_transform (GocItem *item, cairo_matrix_t *m)
 void
 _goc_item_transform (GocItem const *item, cairo_t *cr, gboolean scaled)
 {
+       double scale = item->canvas? item->canvas->pixels_per_unit: 1.0;
        cairo_matrix_t m = item->transform, buf,
-               sc = {item->canvas->pixels_per_unit, 0., 0., item->canvas->pixels_per_unit, 0., 0.};
+               sc = {scale, 0., 0., scale, 0., 0.};
        while ((item = GOC_ITEM (item->parent)))
                if (item->transformed) {
                        cairo_matrix_multiply (&buf, &m, &item->transform);
@@ -905,3 +906,57 @@ goc_item_get_style_context (const GocItem *item)
        return context;
 }
 #endif
+
+/**
+ * goc_item_duplicate:
+ * @item: #GocItem
+ * @parent: #GocGroup
+ *
+ * Creates a new GocItem identical to @item inside the parent GocGroup if not
+ * NULL.
+ *
+ * Returns: (transfer none): The duplicated item or NULL if the duplication was
+ * not possible.
+ */
+GocItem*
+goc_item_duplicate (GocItem *item, GocGroup *parent)
+{
+       GocItemClass *klass;
+       GocItem *ret;
+
+       g_return_val_if_fail (GOC_IS_ITEM (item), NULL);
+
+       klass = GOC_ITEM_GET_CLASS (item);
+       if (klass->copy == NULL)
+               return NULL;
+
+       ret = GOC_ITEM ((parent)? goc_item_new (parent, G_OBJECT_TYPE (item), NULL):
+                                                         g_object_new (G_OBJECT_TYPE (item), NULL));
+       
+       klass->copy (ret, item);
+       return ret;
+}
+
+/**
+ * goc_item_copy:
+ * source: #GocItem
+ * dest: #GocItem
+ *
+ * Copies @source properties to @dest. The two items must be of the same type
+ * and their common class needs a @copy member.
+ **/
+void
+goc_item_copy (GocItem *dest, GocItem *source)
+{
+       GocItemClass *klass = GOC_ITEM_GET_CLASS (source);
+
+       g_return_if_fail (GOC_IS_ITEM (source));
+       g_return_if_fail (GOC_IS_ITEM (dest));
+       g_return_if_fail (klass == GOC_ITEM_GET_CLASS (dest));
+       g_return_if_fail (klass->copy);
+       dest->visible = source->visible;
+       dest->op = source->op;
+       dest->transform = source->transform;
+       dest->transformed = source->transformed;
+       klass->copy (dest, source);
+}
diff --git a/goffice/canvas/goc-item.h b/goffice/canvas/goc-item.h
index 6d7d9487..eff86c2b 100644
--- a/goffice/canvas/goc-item.h
+++ b/goffice/canvas/goc-item.h
@@ -36,7 +36,7 @@ struct _GocItem {
        gboolean                 realized;
        double                   x0, y0, x1, y1; /* the bounds */
        cairo_operator_t         op;
-       cairo_matrix_t          transform; /* not used for now */
+       cairo_matrix_t          transform; /* unused for now */
        gboolean                transformed; /* TRUE if the matrix is not identity */
 
        /* FIXME: Next development release needs to add style context and
@@ -70,9 +70,9 @@ struct _GocItemClass {
        gboolean                (*key_released) (GocItem *item, GdkEventKey* ev);
        GdkWindow*              (*get_window) (GocItem *item);
 #endif
+       void            (*copy) (GocItem *source, GocItem *dest);
 
        /* <private> */
-       void (*reserved1) (void);
        void (*reserved2) (void);
        void (*reserved3) (void);
        void (*reserved4) (void);
@@ -121,6 +121,8 @@ void                 _goc_item_transform    (GocItem const *item, cairo_t *cr,
 void            goc_item_set_operator  (GocItem *item, cairo_operator_t op);
 cairo_operator_t goc_item_get_operator  (GocItem *item);
 void            goc_item_set_transform (GocItem *item, cairo_matrix_t *m);
+void            goc_item_copy (GocItem *dest, GocItem *source);
+GocItem                *goc_item_duplicate (GocItem *item, GocGroup *parent);
 
 #ifdef GOFFICE_WITH_GTK
 GtkStyleContext *goc_item_get_style_context (const GocItem *item);
diff --git a/goffice/canvas/goc-line.c b/goffice/canvas/goc-line.c
index 88f2a9ac..455e31a0 100644
--- a/goffice/canvas/goc-line.c
+++ b/goffice/canvas/goc-line.c
@@ -32,6 +32,8 @@
  * arrows at the start and/or at the end.
 **/
 
+static GocItemClass *parent_class;
+
 enum {
        LINE_PROP_0,
        LINE_PROP_X0,
@@ -225,7 +227,7 @@ goc_line_draw (GocItem const *item, cairo_t *cr)
 {
        GocLine *line = GOC_LINE (item);
        GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
        double endx = (line->endx - line->startx) * sign, endy = line->endy - line->starty;
        double hoffs, voffs = ceil (style->line.width);
        double startx = 0, starty = 0;
@@ -267,6 +269,20 @@ goc_line_draw (GocItem const *item, cairo_t *cr)
        cairo_restore (cr);
 }
 
+static void
+goc_line_copy (GocItem *dest, GocItem *source)
+{
+       GocLine *src = GOC_LINE (source), *dst = GOC_LINE (dest);
+
+       dst->startx = src->startx;
+       dst->starty = src->starty;
+       dst->endx = src->endx;
+       dst->endy = src->endy;
+       dst->start_arrow = src->start_arrow;
+       dst->end_arrow = src->end_arrow;
+       parent_class->copy (dest, source);
+}
+
 static void
 goc_line_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -284,6 +300,7 @@ goc_line_class_init (GocItemClass *item_klass)
 {
        GObjectClass *obj_klass = (GObjectClass *) item_klass;
        GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+       parent_class = g_type_class_peek_parent (item_klass);
 
        gsi_klass->init_style = goc_line_init_style;
 
@@ -329,6 +346,7 @@ goc_line_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_line_update_bounds;
        item_klass->distance = goc_line_distance;
        item_klass->draw = goc_line_draw;
+       item_klass->copy = goc_line_copy;
 }
 
 GSF_CLASS (GocLine, goc_line,
diff --git a/goffice/canvas/goc-path.c b/goffice/canvas/goc-path.c
index 65297293..4886d785 100644
--- a/goffice/canvas/goc-path.c
+++ b/goffice/canvas/goc-path.c
@@ -123,7 +123,7 @@ static gboolean
 goc_path_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
 {
        GocPath *path = GOC_PATH (item);
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
 
        _goc_item_transform (item, cr, flag);
        if (1 == flag) {
@@ -232,6 +232,20 @@ goc_path_draw (GocItem const *item, cairo_t *cr)
                cairo_restore(cr);
 }
 
+static void
+goc_path_copy (GocItem *dest, GocItem *source)
+{
+       GocPath *src = GOC_PATH (source), *dst = GOC_PATH (dest);
+
+       dst->rotation = src->rotation;
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->closed = src->closed;
+       dst->fill_rule = src->fill_rule;
+       dst->path = go_path_copy (src->path);
+       ((GocItemClass *) parent_class)->copy (dest, source);
+}
+
 static void
 goc_path_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -314,6 +328,7 @@ goc_path_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_path_update_bounds;
        item_klass->distance = goc_path_distance;
        item_klass->draw = goc_path_draw;
+       item_klass->copy = goc_path_copy;
 }
 
 GSF_CLASS (GocPath, goc_path,
diff --git a/goffice/canvas/goc-pixbuf.c b/goffice/canvas/goc-pixbuf.c
index 2b8f3918..95cfd6da 100644
--- a/goffice/canvas/goc-pixbuf.c
+++ b/goffice/canvas/goc-pixbuf.c
@@ -209,7 +209,7 @@ goc_pixbuf_draw (GocItem const *item, cairo_t *cr)
        }
        cairo_save (cr);
        _goc_item_transform (item, cr, TRUE);
-       x = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)?
+       x = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)?
                pixbuf->x + pixbuf->width: pixbuf->x;
        goc_group_cairo_transform (item->parent, cr, x, (int) pixbuf->y);
        cairo_rotate (cr, pixbuf->rotation);
diff --git a/goffice/canvas/goc-polygon.c b/goffice/canvas/goc-polygon.c
index 5a1201be..8797fc0e 100644
--- a/goffice/canvas/goc-polygon.c
+++ b/goffice/canvas/goc-polygon.c
@@ -176,11 +176,11 @@ goc_polygon_prepare_path (GocItem const *item, cairo_t *cr, gboolean flag)
                cairo_save (cr);
                if (flag == 0)
                        cairo_translate (cr, polygon->points[0].x, polygon->points[0].y);
-               go_bezier_spline_to_cairo (spline, cr, goc_canvas_get_direction (item->canvas) == 
GOC_DIRECTION_RTL);
+               go_bezier_spline_to_cairo (spline, cr, item->canvas && goc_canvas_get_direction 
(item->canvas) == GOC_DIRECTION_RTL);
                cairo_restore (cr);
        } else {
                /* sign is meaningful only for drawing, so if flag == 0, sign must be 1 */
-               double sign = (flag && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+               double sign = (flag && item->canvas && goc_canvas_get_direction (item->canvas) == 
GOC_DIRECTION_RTL)? -1: 1;
                if (polygon->nb_sizes > 0) {
                        snum = 0;
                        for (j = 0; j < (int) polygon->nb_sizes; j++) {
@@ -309,6 +309,30 @@ goc_polygon_draw (GocItem const *item, cairo_t *cr)
                cairo_restore (cr);
 }
 
+static void
+goc_polygon_copy (GocItem *dest, GocItem *source)
+{
+       GocPolygon *src = GOC_POLYGON (source), *dst = GOC_POLYGON (dest);
+       unsigned ui;
+       
+       dst->nb_points = src->nb_points;
+       dst->use_spline = src->use_spline;
+       dst->fill_rule = src->fill_rule;
+       if (src->nb_points > 0) {
+               dst->points = g_new (GocPoint, src->nb_points);
+               for (ui = 0; ui < src->nb_points; ui++)
+                       dst->points[ui] = src->points[ui];
+       } else
+               dst->points = NULL;
+       if (src->nb_sizes > 0) {
+               dst->sizes = g_new (int, src->nb_sizes);
+               for (ui = 0; ui < src->nb_sizes; ui++)
+                       dst->sizes[ui] = src->sizes[ui];
+       } else
+               dst->sizes = NULL;
+       ((GocItemClass *) parent_class)->copy (dest, source);
+}
+
 static void
 goc_polygon_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -366,6 +390,7 @@ goc_polygon_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_polygon_update_bounds;
        item_klass->distance = goc_polygon_distance;
        item_klass->draw = goc_polygon_draw;
+       item_klass->copy = goc_polygon_copy;
 }
 
 GSF_CLASS (GocPolygon, goc_polygon,
diff --git a/goffice/canvas/goc-polyline.c b/goffice/canvas/goc-polyline.c
index 559748ec..55e9322f 100644
--- a/goffice/canvas/goc-polyline.c
+++ b/goffice/canvas/goc-polyline.c
@@ -131,10 +131,10 @@ goc_polyline_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
                cairo_save (cr);
                if (flag == 0)
                        cairo_translate (cr, polyline->points[0].x, polyline->points[0].y);
-               go_bezier_spline_to_cairo (spline, cr, goc_canvas_get_direction (item->canvas) == 
GOC_DIRECTION_RTL);
+               go_bezier_spline_to_cairo (spline, cr, item->canvas && goc_canvas_get_direction 
(item->canvas) == GOC_DIRECTION_RTL);
                cairo_restore (cr);
        } else {
-               double sign = (flag && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1: 1;
+               double sign = (flag && item->canvas && goc_canvas_get_direction (item->canvas) == 
GOC_DIRECTION_RTL)? -1: 1;
                gboolean prev_valid = TRUE;
                for (i = 1; i < polyline->nb_points; i++) {
                        if (go_finite (polyline->points[i].x)) {
@@ -226,6 +226,23 @@ goc_polyline_draw (GocItem const *item, cairo_t *cr)
        }
 }
 
+static void
+goc_polyline_copy (GocItem *dest, GocItem *source)
+{
+       GocPolyline *src = GOC_POLYLINE (source), *dst = GOC_POLYLINE (dest);
+       
+       dst->nb_points = src->nb_points;
+       dst->use_spline = src->use_spline;
+       if (src->nb_points > 0) {
+               unsigned ui;
+               dst->points = g_new (GocPoint, src->nb_points);
+               for (ui = 0; ui < src->nb_points; ui++)
+                       dst->points[ui] = src->points[ui];
+       } else
+               dst->points = NULL;
+       ((GocItemClass *) parent_class)->copy (dest, source);
+}
+
 static void
 goc_polyline_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -270,6 +287,7 @@ goc_polyline_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_polyline_update_bounds;
        item_klass->distance = goc_polyline_distance;
        item_klass->draw = goc_polyline_draw;
+       item_klass->copy = goc_polyline_copy;
 }
 
 GSF_CLASS (GocPolyline, goc_polyline,
diff --git a/goffice/canvas/goc-rectangle.c b/goffice/canvas/goc-rectangle.c
index 9549ea7f..eee35b84 100644
--- a/goffice/canvas/goc-rectangle.c
+++ b/goffice/canvas/goc-rectangle.c
@@ -32,6 +32,8 @@
  * #GocPolygon implements rectangle drawing in the canvas.
 **/
 
+static GocItemClass *parent_klass;
+
 enum {
        RECT_PROP_0,
        RECT_PROP_X,
@@ -138,7 +140,7 @@ static gboolean
 goc_rectangle_prepare_draw (GocItem const *item, cairo_t *cr, gboolean flag)
 {
        GocRectangle *rect = GOC_RECTANGLE (item);
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
 
        if (0 == rect->width && 0 == rect->height)
                return FALSE;
@@ -306,11 +308,28 @@ goc_rectangle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
                style->fill.pattern.back = GO_COLOR_WHITE;
 }
 
+static void
+goc_rectangle_copy (GocItem *dest, GocItem *source)
+{
+       GocRectangle *src = GOC_RECTANGLE (source), *dst = GOC_RECTANGLE (dest);
+
+       dst->rotation = src->rotation;
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->width = src->width;
+       dst->height = src->height;
+       dst->type = src->type;
+       dst->rx = src->rx;
+       dst->ry = src->ry;
+       parent_klass->copy (dest, source);
+}
+
 static void
 goc_rectangle_class_init (GocItemClass *item_klass)
 {
        GObjectClass *obj_klass = (GObjectClass *) item_klass;
        GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+       parent_klass = g_type_class_peek_parent (item_klass);
 
        obj_klass->get_property = goc_rectangle_get_property;
        obj_klass->set_property = goc_rectangle_set_property;
@@ -368,6 +387,7 @@ goc_rectangle_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_rectangle_update_bounds;
        item_klass->distance = goc_rectangle_distance;
        item_klass->draw = goc_rectangle_draw;
+       item_klass->copy = goc_rectangle_copy;
 }
 
 GSF_CLASS (GocRectangle, goc_rectangle,
diff --git a/goffice/canvas/goc-styled-item.c b/goffice/canvas/goc-styled-item.c
index 71be514a..5aa78891 100644
--- a/goffice/canvas/goc-styled-item.c
+++ b/goffice/canvas/goc-styled-item.c
@@ -127,6 +127,14 @@ goc_styled_item_init_style (GocStyledItem *gsi, GOStyle *style)
        style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL; /* default */
 }
 
+static void
+goc_styled_item_copy (GocItem *dest, GocItem *source)
+{
+       GOStyle *style = go_style_dup (((GocStyledItem *) source)->style);
+       g_object_set (dest, "style", style, NULL);
+       g_object_unref (style);
+}
+
 static void
 goc_styled_item_class_init (GocItemClass *goc_klass)
 {
@@ -156,6 +164,7 @@ goc_styled_item_class_init (GocItemClass *goc_klass)
        gobject_klass->get_property = goc_styled_item_get_property;
        gobject_klass->finalize     = goc_styled_item_finalize;
        style_klass->init_style     = goc_styled_item_init_style;
+       goc_klass->copy                 = goc_styled_item_copy;
 
        g_object_class_install_property (gobject_klass, STYLED_ITEM_PROP_STYLE,
                g_param_spec_object ("style",
@@ -239,7 +248,7 @@ goc_styled_item_style_changed (GOStyledObject *gsi)
 static GODoc*
 goc_styled_item_get_document (GOStyledObject *gsi)
 {
-       return goc_canvas_get_document (GOC_ITEM (gsi)->canvas);
+       return (GOC_ITEM (gsi)->canvas)? goc_canvas_get_document (GOC_ITEM (gsi)->canvas): NULL;
 }
 
 static void
@@ -281,7 +290,7 @@ goc_styled_item_set_cairo_line  (GocStyledItem const *gsi, cairo_t *cr)
        g_return_val_if_fail (GOC_IS_STYLED_ITEM (gsi), FALSE);
 
        /* scale the line width */
-       if (gsi->scale_line_width) {
+       if (gsi->scale_line_width && GOC_ITEM (gsi)->canvas) {
                width = gsi->style->line.width;
                gsi->style->line.width *= goc_canvas_get_pixels_per_unit (GOC_ITEM (gsi)->canvas);
        }
diff --git a/goffice/canvas/goc-text.c b/goffice/canvas/goc-text.c
index a7010532..d8863df4 100644
--- a/goffice/canvas/goc-text.c
+++ b/goffice/canvas/goc-text.c
@@ -214,7 +214,7 @@ goc_text_prepare_draw (GocItem *item, cairo_t *cr, gboolean flag)
 {
        GocText *text = GOC_TEXT (item);
        PangoRectangle rect;
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
        double w, h, dx, dy;
        PangoLayout *pl;
        GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
@@ -235,7 +235,7 @@ goc_text_prepare_draw (GocItem *item, cairo_t *cr, gboolean flag)
        pango_layout_get_extents (pl, NULL, &rect);
        text->w = (double) rect.width / PANGO_SCALE;
        text->h = (double) rect.height / PANGO_SCALE;
-       item->x0 = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? text->x + text->w: text->x;
+       item->x0 = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? text->x + 
text->w: text->x;
        item->y0 = text->y;
        dx = dy = 0;
        w = (text->clip_width > 0.)? MIN (text->clip_width, text->w): text->w;
@@ -336,9 +336,9 @@ static void
 goc_text_draw (GocItem const *item, cairo_t *cr)
 {
        GocText *text = GOC_TEXT (item);
-       double x = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? text->x + text->w: text->x,
+       double x = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? text->x + 
text->w: text->x,
               y = text->y, dx = 0., dy = 0., h, w;
-       double sign = (goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
+       double sign = (item->canvas && goc_canvas_get_direction (item->canvas) == GOC_DIRECTION_RTL)? -1.: 1.;
 
        PangoLayout *pl;
        GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
@@ -419,6 +419,26 @@ goc_text_draw (GocItem const *item, cairo_t *cr)
        g_object_unref (pl);
 }
 
+static void
+goc_text_copy (GocItem *dest, GocItem *source)
+{
+       GocText *src = GOC_TEXT (source), *dst = GOC_TEXT (dest);
+
+       dst->x = src->x;
+       dst->y = src->y;
+       dst->w = src->w;
+       dst->h = src->h;
+       dst->rotation = src->rotation;
+       dst->clipped = src->clipped;
+       dst->clip_width = src->clip_width;
+       dst->clip_height = src->clip_height;
+       dst->wrap_width = src->wrap_width;
+       dst->text = g_strdup (src->text);
+       dst->anchor = src->anchor;
+       dst->attributes = pango_attr_list_copy (src->attributes);
+       parent_class->copy (dest, source);
+}
+
 static void
 goc_text_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
 {
@@ -506,6 +526,7 @@ goc_text_class_init (GocItemClass *item_klass)
        item_klass->update_bounds = goc_text_update_bounds;
        item_klass->distance = goc_text_distance;
        item_klass->draw = goc_text_draw;
+       item_klass->copy = goc_text_copy;
 }
 
 static void
diff --git a/goffice/utils/go-emf.c b/goffice/utils/go-emf.c
index c1b1ad0e..ce95e5b8 100644
--- a/goffice/utils/go-emf.c
+++ b/goffice/utils/go-emf.c
@@ -30,7 +30,7 @@
 
 struct _GOEmf {
        GOImage parent;
-       GocCanvas *canvas;
+       GocGroup *group;
 };
 
 typedef GOImageClass GOEmfClass;
@@ -104,8 +104,8 @@ static void
 go_emf_draw (GOImage *image, cairo_t *cr)
 {
        GOEmf *emf = GO_EMF (image);
-       g_return_if_fail (emf && emf->canvas);
-       goc_canvas_render (emf->canvas, cr, 0, 0, image->width, image->height);
+       g_return_if_fail (emf && emf->group);
+       goc_item_draw_region ((GocItem *) emf->group, cr, 0, 0, image->width, image->height);
 }
 
 static GdkPixbuf *
@@ -118,7 +118,7 @@ go_emf_get_pixbuf (GOImage *image)
        g_return_val_if_fail (emf, NULL);
        surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, image->width, image->height);
        cr = cairo_create (surface);
-       goc_canvas_render (emf->canvas, cr, 0, 0, image->width, image->height);
+       goc_item_draw_region ((GocItem *) emf->group, cr, 0, 0, image->width, image->height);
        cairo_destroy (cr);
        res = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, image->width, image->height);
        go_cairo_convert_data_from_pixbuf (gdk_pixbuf_get_pixels (res),
@@ -139,7 +139,7 @@ go_emf_get_scaled_pixbuf (GOImage *image, int width, int height)
        surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
        cr = cairo_create (surface);
        cairo_scale (cr, width / image->width, height / image->height);
-       goc_canvas_render (emf->canvas, cr, 0, 0, image->width, image->height);
+       goc_item_draw_region ((GocItem *) emf->group, cr, 0, 0, image->width, image->height);
        cairo_destroy (cr);
        res = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
        go_cairo_convert_data_from_pixbuf (gdk_pixbuf_get_pixels (res),
@@ -162,8 +162,8 @@ static void
 go_emf_finalize (GObject *obj)
 {
        GOEmf *emf = GO_EMF (obj);
-       if (emf->canvas != NULL)
-               g_object_unref (emf->canvas);
+       if (emf->group != NULL)
+               g_object_unref (emf->group);
        (parent_klass->finalize) (obj);
 }
 
@@ -189,7 +189,7 @@ go_emf_class_init (GObjectClass *klass)
 static void
 go_emf_init (GOEmf *emf)
 {
-       emf->canvas = g_object_ref_sink (g_object_new (GOC_TYPE_CANVAS, NULL));
+       emf->group = g_object_new (GOC_TYPE_GROUP, NULL);
 }
 
 GSF_CLASS (GOEmf, go_emf,
@@ -200,14 +200,18 @@ GSF_CLASS (GOEmf, go_emf,
  * go_emf_get_canvas:
  * @emf: #GOEmf
  *
- * Returns: (transfer full): the canvas displaying the EMF image, adding a
- * reference to it.
+ * Returns: (transfer full): a GocCanvas displaying the EMF image.
  **/
 GObject *
 go_emf_get_canvas (GOEmf *emf)
 {
+       GocCanvas *canvas;
+
        g_return_val_if_fail (GO_IS_EMF (emf), NULL);
-       return (GObject *)g_object_ref (emf->canvas);
+
+       canvas = GOC_CANVAS (g_object_new (GOC_TYPE_CANVAS, NULL));
+       goc_item_copy ((GocItem *) goc_canvas_get_root (canvas), (GocItem *) emf->group);
+       return (GObject *) canvas;
 }
 
 GOImage *
@@ -245,7 +249,7 @@ go_emf_new_from_file (char const *filename, GError **error)
                }
        } else if (image->width == 0 || image->height == 0) {
                double x0, y0, x1, y1;
-               goc_canvas_get_bounds (emf->canvas, &x0, &y0, &x1, &y1);
+               goc_item_get_bounds ((GocItem *) emf->group, &x0, &y0, &x1, &y1);
                image->width = x1;
                image->height = y1;
        }
@@ -282,7 +286,7 @@ go_emf_new_from_data (char const *data, size_t length, GError **error)
                }
        } else if (image->width == 0 || image->height == 0) {
                double x0, y0, x1, y1;
-               goc_canvas_get_bounds (emf->canvas, &x0, &y0, &x1, &y1);
+               goc_item_get_bounds ((GocItem *) emf->group, &x0, &y0, &x1, &y1);
                image->width = x1;
                image->height = y1;
        }
@@ -961,7 +965,7 @@ typedef struct {
 
 typedef struct {
        unsigned version;
-       GocCanvas *canvas;
+       GocGroup *group;
        GError **error;
        guint8 const *data;
        unsigned length;
@@ -1243,7 +1247,7 @@ go_wmf_set_align (GsfInput* input, GOWmfPage* pg, double* x, double* y)
 }
 
 static void
-go_wmf_set_text (GOWmfPage* pg, GocCanvas* canvas, char* txt, int len, GOAnchorType* anchor, double* x, 
double* y)
+go_wmf_set_text (GOWmfPage* pg, GocGroup *group, char* txt, int len, GOAnchorType* anchor, double* x, 
double* y)
 {
        GocItem *gocitem;
        char *utxt;
@@ -1268,7 +1272,7 @@ go_wmf_set_text (GOWmfPage* pg, GocCanvas* canvas, char* txt, int len, GOAnchorT
        } else {
                utxt = g_convert (txt, len, "utf8", "ASCII", NULL, NULL, NULL);
        }
-       gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_TEXT,
+       gocitem = goc_item_new (group, GOC_TYPE_TEXT,
                                        "x", *x, "y", *y, "text", utxt, "anchor", *anchor, NULL);
        go_wmf_set_font (pg, gocitem);
 }
@@ -1414,14 +1418,14 @@ go_wmf_fill (GOWmfPage *pg, GocItem *item)
 
 
 static void
-go_wmf_mr0 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr0 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        d_ (("!EOF\n"));
 }
 
 /* -------------- SaveDC ---------------- */
 static void
-go_wmf_mr1 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr1 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC mydc;
 
@@ -1432,20 +1436,20 @@ go_wmf_mr1 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCa
 }
 
 static void
-go_wmf_mr2 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr2 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        d_ (("RealizePalette: unimplemeted\n"));
 }
 
 static void
-go_wmf_mr3 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr3 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        d_ (("SetPalEntries: unimplemented\n"));
 }
 
 /* ------------- CreatePalette ------------ */
 static void
-go_wmf_mr4 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr4 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        /* FIXME: do actual parsing */
        GOWmfMFobj *mf;
@@ -1458,7 +1462,7 @@ go_wmf_mr4 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCa
 
 /* ------------- SetBKMode ----------------- */
 static void
-go_wmf_mr5 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr5 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfDC *dc;
@@ -1471,27 +1475,27 @@ go_wmf_mr5 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCa
 }
 
 static void
-go_wmf_mr6 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr6 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        d_ (("SetMapMode: unimplemeted\n"));
 }
 
 static void
-go_wmf_mr7 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr7 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetROP2 "));*/
 }
 
 /* ------------- SetReLabs ------------- */
 static void
-go_wmf_mr8 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr8 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        /* FIXME: Exclude, should never be used */
 }
 
 /* ----------------- SetPolyfillMode ----------------- */
 static void
-go_wmf_mr9 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr9 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfDC *dc;
@@ -1506,20 +1510,20 @@ go_wmf_mr9 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCa
 }
 
 static void
-go_wmf_mr10 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr10 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetStrechBLTMode "));*/
 }
 
 static void
-go_wmf_mr11 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr11 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetTextCharExtra "));*/
 }
 
 /* ---------------- RestoreDC ----------------------- */
 static void
-go_wmf_mr12 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr12 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        gint16 idx;
@@ -1534,26 +1538,26 @@ go_wmf_mr12 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr13 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr13 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("InvertRegion "));*/
 }
 
 static void
-go_wmf_mr14 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr14 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("PaintRegion "));*/
 }
 
 static void
-go_wmf_mr15 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas *canvas)
+go_wmf_mr15 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SelectClipRegion "));*/
 }
 
 /* -------------------- Select Object ----------------- */
 static void
-go_wmf_mr16 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr16 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        int idx;
@@ -1589,7 +1593,7 @@ go_wmf_mr16 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* ---------------- SetTextAlign ----------------------- */
 static void
-go_wmf_mr17 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr17 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfDC *dc;
@@ -1601,14 +1605,14 @@ go_wmf_mr17 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr18 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr18 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("ResizePalette "));*/
 }
 
 /* --------------- DIBCreatePatternBrush -------------- */
 static void
-go_wmf_mr19 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr19 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfBrush *brush;
@@ -1679,14 +1683,14 @@ go_wmf_mr19 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* -------------- SetLayout -------------------- */
 static void
-go_wmf_mr20 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr20 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 
 }
 
 /* -------------- DeleteObject -------------------- */
 static void
-go_wmf_mr21 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr21 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        int idx;
@@ -1699,7 +1703,7 @@ go_wmf_mr21 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  -------------- CreatePatternBrush -------------------- */
 static void
-go_wmf_mr22 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr22 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        /* FIXME: add pixbufloader */
        GOWmfMFobj *mf;
@@ -1711,7 +1715,7 @@ go_wmf_mr22 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  -------------- SetBKColor -------------------- */
 static void
-go_wmf_mr23 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr23 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1722,7 +1726,7 @@ go_wmf_mr23 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  -------------- SetTextColor -------------------- */
 static void
-go_wmf_mr24 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr24 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1732,14 +1736,14 @@ go_wmf_mr24 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr25 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr25 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetTextJustification "));*/
 }
 
 /* ---------------- SetWindowOrg ----------------- */
 static void
-go_wmf_mr26 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr26 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1750,7 +1754,7 @@ go_wmf_mr26 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  ---------------- SetWindowExt ------------------- */
 static void
-go_wmf_mr27 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr27 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1771,7 +1775,7 @@ go_wmf_mr27 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  ----------------- SetViewportOrg ------------------- */
 static void
-go_wmf_mr28 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr28 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1782,7 +1786,7 @@ go_wmf_mr28 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  ----------------- SetViewportExt -------------------- */
 static void
-go_wmf_mr29 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr29 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
 
@@ -1793,7 +1797,7 @@ go_wmf_mr29 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* ------------------- OffsetWindowOrg ------------------ */
 static void
-go_wmf_mr30 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr30 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
        double x,y;
@@ -1807,7 +1811,7 @@ go_wmf_mr30 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* ------------------- OffsetViewportOrg ---------------- */
 static void
-go_wmf_mr31 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr31 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        GOWmfDC *dc;
        double x,y;
@@ -1821,7 +1825,7 @@ go_wmf_mr31 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  ------------------ LineTo -------------------- */
 static void
-go_wmf_mr32 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr32 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        double x,y;
        GocItem *gocitem;
@@ -1831,7 +1835,7 @@ go_wmf_mr32 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
        go_wmf_read_point (input, &y, &x);
        gsf_input_seek (input, -4, G_SEEK_CUR);
        go_wmf_mr_convcoord (&x, &y, pg);
-       gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_LINE,
+       gocitem = goc_item_new (group, GOC_TYPE_LINE,
                "x0", dc->curx, "y0", dc->cury, "x1", x, "y1", y, NULL);
        dc->curx = x;
        dc->cury = y;
@@ -1840,7 +1844,7 @@ go_wmf_mr32 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /*  ------------------ MoveTo -------------------- */
 static void
-go_wmf_mr33 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr33 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        double x,y;
        GOWmfDC *dc;
@@ -1854,32 +1858,32 @@ go_wmf_mr33 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr34 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr34 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("OffsetClipRgn "));*/
 }
 
 static void
-go_wmf_mr35 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr35 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("FillRegion "));*/
 }
 
 static void
-go_wmf_mr36 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr36 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetMapperFlags "));*/
 }
 
 static void
-go_wmf_mr37 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr37 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SelectPalette "));*/
 }
 
 /*  ------------------ CreatePenIndirect ------------------- */
 static void
-go_wmf_mr38 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr38 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfPen *pen;
@@ -1905,7 +1909,7 @@ go_wmf_mr38 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* ----------------- CreateFontIndirect ------------- */
 static void
-go_wmf_mr39 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr39 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        GOWmfFont *font;
@@ -2004,7 +2008,7 @@ go_wmf_mr39 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 
 /* ---------------- CreateBrushIndirect --------------- */
 static void
-go_wmf_mr40 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr40 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8 *data = {0};
        GOWmfBrush *brush;
@@ -2025,7 +2029,7 @@ go_wmf_mr40 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr_poly (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
+go_wmf_mr_poly (GsfInput* input, GOWmfPage* pg, GocGroup *group, int type)
 {
        const guint8  *data = {0};
        double len;
@@ -2044,9 +2048,9 @@ go_wmf_mr_poly (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
        }
 
        if (0 == type)
-               gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_POLYGON, "points", points, 
"fill-rule", dc->pfm, NULL);
+               gocitem = goc_item_new (group, GOC_TYPE_POLYGON, "points", points, "fill-rule", dc->pfm, 
NULL);
        else
-               gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_POLYLINE, "points", points, 
NULL);
+               gocitem = goc_item_new (group, GOC_TYPE_POLYLINE, "points", points, NULL);
        go_wmf_fill (pg,gocitem);
        go_wmf_stroke (pg,gocitem);
        gsf_input_seek (input, -len * 4 - 2, G_SEEK_CUR);
@@ -2054,44 +2058,44 @@ go_wmf_mr_poly (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
 
 /*  ---------- Polygon ---------------- */
 static void
-go_wmf_mr41 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr41 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_poly (input, pg, canvas, 0);
+       go_wmf_mr_poly (input, pg, group, 0);
 }
 
 /*  ---------- Polyline ---------------- */
 static void
-go_wmf_mr42 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr42 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_poly (input, pg, canvas, 1);
+       go_wmf_mr_poly (input, pg, group, 1);
 }
 
 static void
-go_wmf_mr43 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr43 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("ScaleWindowExtEx "));*/
 }
 
 static void
-go_wmf_mr44 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr44 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("ScaleViewportExt "));*/
 }
 
 static void
-go_wmf_mr45 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr45 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("ExcludeClipRect "));*/
 }
 
 static void
-go_wmf_mr46 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr46 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("IntersectClipRect "));*/
 }
 
 static void
-go_wmf_mr_rect (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
+go_wmf_mr_rect (GsfInput* input, GOWmfPage* pg, GocGroup *group, int type)
 {
        double x1, x2, y1, y2, tx, ty, rx = 0, ry = 0;
        GocItem *gocitem;
@@ -2117,10 +2121,10 @@ go_wmf_mr_rect (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
        }
 
        if (1 == type)
-               gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_ELLIPSE,
+               gocitem = goc_item_new (group, GOC_TYPE_ELLIPSE,
                        "height", (double) ty, "x", (double) x1, "y", (double) y1, "width", (double) tx, 
NULL);
        else
-               gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_RECTANGLE,
+               gocitem = goc_item_new (group, GOC_TYPE_RECTANGLE,
                        "height", (double) ty, "x", (double) x1, "y", (double) y1, "width",
                        (double) tx, "rx", (double) rx, "ry", (double) ry, "type", type, NULL);
        go_wmf_fill (pg, gocitem);
@@ -2130,45 +2134,45 @@ go_wmf_mr_rect (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
 
 /* ----------------- Ellipse --------------- */
 static void
-go_wmf_mr47 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr47 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_rect (input, pg, canvas, 1);
+       go_wmf_mr_rect (input, pg, group, 1);
 }
 
 static void
-go_wmf_mr48 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr48 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("FloodFill "));*/
 }
 
 /*  ---------------- Rectangle -------------- */
 static void
-go_wmf_mr49 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr49 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_rect (input, pg, canvas, 0);
+       go_wmf_mr_rect (input, pg, group, 0);
 }
 
 static void
-go_wmf_mr50 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr50 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetPixel "));*/
 }
 
 static void
-go_wmf_mr51 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr51 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("FrameRegion "));*/
 }
 
 static void
-go_wmf_mr52 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr52 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("AnimatePalette "));*/
 }
 
 /*---------------- TextOut -------------------- */
 static void
-go_wmf_mr53 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr53 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        char *txt;
@@ -2187,12 +2191,12 @@ go_wmf_mr53 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
        }
        go_wmf_set_align (input, pg, &x, &y);
        gsf_input_seek (input, -6 - len - shift, G_SEEK_CUR);
-       go_wmf_set_text (pg, canvas, txt, len, &anchor, &x, &y);
+       go_wmf_set_text (pg, group, txt, len, &anchor, &x, &y);
 }
 
 /*  ------------ PolyPolygon ------------ */
 static void
-go_wmf_mr54 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr54 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        double x, y;
@@ -2225,7 +2229,7 @@ go_wmf_mr54 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
                        points->points[i].y = y;
        }
 
-       gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_POLYGON,
+       gocitem = goc_item_new (group, GOC_TYPE_POLYGON,
                "points", points, "sizes", array, "fill-rule", dc->pfm, NULL);
        go_wmf_fill (pg, gocitem);
        go_wmf_stroke (pg, gocitem);
@@ -2233,35 +2237,35 @@ go_wmf_mr54 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr55 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr55 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("ExtFloodFill "));*/
 }
 
 /*  ---------------- RoundRect ---------------------- */
 static void
-go_wmf_mr56 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr56 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_rect (input, pg, canvas, 15);
+       go_wmf_mr_rect (input, pg, group, 15);
        gsf_input_seek (input, -4, G_SEEK_CUR);
 }
 
 static void
-go_wmf_mr57 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr57 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("PatBLT "));*/
 }
 
 /* ------------------ Escape ------------------------ */
 static void
-go_wmf_mr58 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr58 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 
 }
 
 /* ------------------ CreateRegion ------------------ */
 static void
-go_wmf_mr59 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr59 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        /* FIXME: do actual parsing */
        GOWmfMFobj *mf;
@@ -2272,7 +2276,7 @@ go_wmf_mr59 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
 }
 
 static void
-go_wmf_mr_arc (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
+go_wmf_mr_arc (GsfInput* input, GOWmfPage* pg, GocGroup *group, int type)
 {
        GOWmfArc *arc;
        GocItem *gocitem;
@@ -2301,7 +2305,7 @@ go_wmf_mr_arc (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
        arc->t = ry;
        arc->l = a1;
        arc->b = a2;
-       gocitem = goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_ARC,
+       gocitem = goc_item_new (group, GOC_TYPE_ARC,
         "xc", arc->xs, "yc", arc->ys, "xr",arc->r, "yr", arc->t,
         "ang1",arc->l, "ang2", arc->b,"type", type, NULL);
        go_wmf_stroke (pg, gocitem);
@@ -2311,40 +2315,40 @@ go_wmf_mr_arc (GsfInput* input, GOWmfPage* pg, GocCanvas* canvas, int type)
 
 /*  ---------------- Arc ---------------- */
 static void
-go_wmf_mr60 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr60 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_arc (input, pg, canvas, 0);
+       go_wmf_mr_arc (input, pg, group, 0);
 }
 
 /*  ----------------- Pie ----------------- */
 static void
-go_wmf_mr61 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr61 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_arc (input, pg, canvas, 2);
+       go_wmf_mr_arc (input, pg, group, 2);
 }
 
 /*  ---------------- Chord ------------------ */
 static void
-go_wmf_mr62 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr62 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
-       go_wmf_mr_arc (input, pg, canvas, 1);
+       go_wmf_mr_arc (input, pg, group, 1);
 }
 
 static void
-go_wmf_mr63 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr63 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("BitBLT "));*/
 }
 
 static void
-go_wmf_mr64 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr64 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("DIBBitBLT "));*/
 }
 
 /* ----------------- ExtTextOut ---------------- */
 static void
-go_wmf_mr65 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr65 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        char *txt;
@@ -2361,31 +2365,31 @@ go_wmf_mr65 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
        txt = malloc (sizeof (char) * len + 1);
        gsf_input_read (input, len, txt);
        gsf_input_seek (input, -8 - len, G_SEEK_CUR);
-       go_wmf_set_text (pg, canvas, txt, len, &anchor, &x, &y);
+       go_wmf_set_text (pg, group, txt, len, &anchor, &x, &y);
 }
 
 static void
-go_wmf_mr66 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr66 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("StretchBlt "));*/
 }
 
 /* ----------------- DIBStretchBlt ----------------------- */
 static void
-go_wmf_mr67 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr67 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("DIBStretchBlt "));*/
 }
 
 static void
-go_wmf_mr68 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr68 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
 /*     g_print("SetDIBtoDEV "));*/
 }
 
 /* ---------------- StretchDIB -------------------- */
 static void
-go_wmf_mr69 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas)
+go_wmf_mr69 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup *group)
 {
        const guint8  *data = {0};
        double x, y, xe, ye, w, h;
@@ -2448,12 +2452,12 @@ go_wmf_mr69 (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocC
        w = xe - x;
        h = ye - y;
 
-       goc_item_new (goc_canvas_get_root (canvas), GOC_TYPE_PIXBUF,
+       goc_item_new (group, GOC_TYPE_PIXBUF,
         "height", (double) h, "x", (double) x, "y", (double) y, "width",(double) w, "pixbuf", gpb, NULL);
 }
 
 typedef void
-(*GOWmfHandler) (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocCanvas* canvas);
+(*GOWmfHandler) (GsfInput* input, guint rsize, GOWmfPage* pg, GHashTable* objs, GocGroup* group);
 
 static GOWmfHandler go_wmf_mfrec_dump[70] =
 {
@@ -2577,7 +2581,7 @@ go_emf_header (GOEmfState *state)
                                 ((double) (state->mmbounds.bottom - state->mmbounds.top)) / 
(state->dubounds.bottom - state->dubounds.top) / 2540. * 72.);
        m.x0 = -(double) state->mmbounds.left / 2540. * 72.;
        m.y0 = -(double) state->mmbounds.top / 2540. * 72.;
-       goc_item_set_transform (GOC_ITEM (goc_canvas_get_root (state->canvas)), &m);
+       goc_item_set_transform (GOC_ITEM (state->group), &m);
 
        return TRUE;
 }
@@ -4159,7 +4163,7 @@ go_emf_stretchdibits (GOEmfState *state)
        if (src_x != 0 || src_y != 0 || src_cx != dst_cx || src_cy != dst_cy) {
                /* FIXME: take src coordinates into account */
        }
-       goc_item_new (goc_canvas_get_root (state->canvas),
+       goc_item_new (state->group,
                      GOC_TYPE_PIXBUF, "pixbuf", pixbuf,
                      "x", (double) dst_x, "y", (double) dst_y,
                      "width", (double) dst_cx, "height", (double) dst_cy,
@@ -4798,7 +4802,7 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
                                break;
                        state.length = rsize;
                        state.data = gsf_input_read (input, rsize, NULL);
-                       state.canvas = emf->canvas;
+                       state.group = emf->group;
                        go_emf_header (&state);
                        image->width = (state.mmbounds.right - state.mmbounds.left) / 2540. * 72.;
                        image->height = (state.mmbounds.bottom - state.mmbounds.top) / 2540. * 72.;
@@ -4849,13 +4853,13 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
                        if (0x626 != rid) {
                                mr = GPOINTER_TO_INT (g_hash_table_lookup (mrecords, GINT_TO_POINTER (rid)));
                                d_ (("Offset: %d, Rid: %x, MR: %d, RSize: %d\n", offset, rid, mr, rsize));
-                               go_wmf_mfrec_dump[mr] (input, rsize, mypg, objs, emf->canvas);
+                               go_wmf_mfrec_dump[mr] (input, rsize, mypg, objs, emf->group);
                        } else {
                                data = gsf_input_read (input, 2, NULL);
                                escfunc = GSF_LE_GET_GINT16 (data);
                                d_ (("ESCAPE! Function is %04x -- %s. Size: %d bytes.\n", escfunc, (char*) 
g_hash_table_lookup (escrecords, GINT_TO_POINTER (escfunc)), rsize * 2 - 6));
                                if (0xf == escfunc)
-                                       go_wmf_mr58 (input, rsize, mypg, objs, emf->canvas);
+                                       go_wmf_mr58 (input, rsize, mypg, objs, emf->group);
                                gsf_input_seek (input, -2, G_SEEK_CUR);
                        }
                        gsf_input_seek (input, rsize * 2 - 6, G_SEEK_CUR);
@@ -4868,13 +4872,14 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
        } else if (type == 3) {
                GOEmfState state;
                state.version = 3;
-               state.canvas = emf->canvas;
+               state.group = emf->group;
                state.error = error;
                state.map_mode = 0;
                state.dc_stack = NULL;
                state.curDC = g_new0 (GOEmfDC, 1);
                state.curDC->style = go_style_new ();
-               state.curDC->group = state.canvas->root;
+               state.curDC->group = state.group;
+               goc_group_freeze (state.group, TRUE);
                state.curDC->text_color = GO_COLOR_BLACK;
                state.dx = state.dy = state.wx = state.wy = 0.;
                state.dw = state.dh = state.ww = state.wh = 1.;
@@ -4902,6 +4907,7 @@ go_emf_parse (GOEmf *emf, GsfInput *input, GError **error)
                                break;
                        rid = GSF_LE_GET_GUINT32 (data);
                }
+               goc_group_freeze (state.group, FALSE);
                go_emf_dc_free (state.curDC);
                g_hash_table_destroy (state.mfobjs);
                if (state.dc_stack != NULL) {
diff --git a/goffice/utils/go-image.c b/goffice/utils/go-image.c
index b532ba1a..61c95ef1 100644
--- a/goffice/utils/go-image.c
+++ b/goffice/utils/go-image.c
@@ -659,9 +659,7 @@ go_image_new_from_data (char const *type, guint8 const *data, gsize length, char
        } else if (!strcmp (type, "svg")) {
                image = go_svg_new_from_data (data, length, error);
        } else if (!strcmp (type, "emf") || !strcmp (type, "wmf")) {
-#warning Remove this when we have a widgetless canvas, see bug #748493
-               if (gdk_screen_get_default () != NULL)
-                       image = go_emf_new_from_data (data, length, error);
+               image = go_emf_new_from_data (data, length, error);
        } else if (!strcmp (type, "eps")) {
                image = go_spectre_new_from_data (data, length, error);
        } else {
@@ -712,13 +710,9 @@ go_image_type_for_format (char const *format)
        g_return_val_if_fail (format && *format, 0);
        if (!strcmp (format, "svg"))
                return GO_TYPE_SVG;
-       if (!strcmp (format, "emf") || !strcmp (format, "wmf")) {
-#warning Remove this when we have a widgetless canvas, see bug #748493
-               if (gdk_screen_get_default() == NULL)
-                       return 0;
+       if (!strcmp (format, "emf") || !strcmp (format, "wmf"))
                return GO_TYPE_EMF;
-       }
-        if (!strcmp (format, "eps"))
+       if (!strcmp (format, "eps"))
                return GO_TYPE_SPECTRE;
        if (go_image_get_format_from_name (format) != GO_IMAGE_FORMAT_UNKNOWN)
                return GO_TYPE_PIXBUF;
diff --git a/tests/mf-demo.c b/tests/mf-demo.c
index dd75b77b..edaa9e04 100644
--- a/tests/mf-demo.c
+++ b/tests/mf-demo.c
@@ -70,6 +70,7 @@ open_file (char const *filename, GtkWidget *nbook)
        }
 
        canvas = GOC_CANVAS (go_emf_get_canvas (GO_EMF (image)));
+       g_object_unref (image);
        g_signal_connect_swapped (canvas, "button-press-event", G_CALLBACK (my_test), canvas);
 
        window = gtk_scrolled_window_new (NULL, NULL);


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