[goffice] Make sheet widgets scalable. [#605434]



commit aa1a6acbe4869832891c5242fad6acc7fc0507fb
Author: Jean Brefort <jean brefort normalesup org>
Date:   Sun Sep 4 15:05:40 2011 +0200

    Make sheet widgets scalable. [#605434]

 ChangeLog                          |    5 +
 NEWS                               |    1 +
 goffice/canvas/goc-widget.c        |  560 ++++++++++++++++++++++++++++++++---
 goffice/canvas/goc-widget.h        |    4 +-
 goffice/graph/gog-axis.c           |    2 +-
 goffice/graph/gog-renderer.c       |    2 +-
 goffice/graph/gog-series-labels.c  |    4 +-
 goffice/graph/gog-smoothed-curve.c |    2 +-
 goffice/gtk/go-format-sel.c        |  106 ++++----
 goffice/utils/go-format.c          |   92 +++---
 goffice/utils/go-string.c          |    4 +-
 plugins/plot_xy/gog-xy.c           |    4 +-
 12 files changed, 629 insertions(+), 157 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index aec29b2..e211ac1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2011-09-04  Jean Brefort  <jean brefort normalesup org>
+
+	* goffice/canvas/goc-widget.c: make sheet widgets scalable. [#605434]
+	* goffice/canvas/goc-widget.h: ditto.
+
 2011-09-03  Andreas J. Guelzow <aguelzow pyrshep ca>
 
 	* goffice/gtk/go-format-sel.ui: new widgets
diff --git a/NEWS b/NEWS
index 897710f..960fabb 100644
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,7 @@ Jean:
 	* Don't crash when pseudo3d axis has too large manual ticks
 	spacing. [#657695]
 	* Use data format for discrete axis. [#641901]
+	* Make sheet widgets scalable. [#605434]
 
 Morten:
 	* Recognize scientific formats with longer exponents.
diff --git a/goffice/canvas/goc-widget.c b/goffice/canvas/goc-widget.c
index c30ad0f..8fc80aa 100644
--- a/goffice/canvas/goc-widget.c
+++ b/goffice/canvas/goc-widget.c
@@ -27,6 +27,463 @@
 
 #include <math.h>
 
+/******************************************************************************
+ * GocOffscreenBox: code mostly copied from gtk+/tests/gtkoffscreenbox.[c,h]
+ ******************************************************************************/
+
+#define GOC_TYPE_OFFSCREEN_BOX              (goc_offscreen_box_get_type ())
+#define GOC_OFFSCREEN_BOX(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOC_TYPE_OFFSCREEN_BOX, GocOffscreenBox))
+#define GOC_OFFSCREEN_BOX_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GOC_TYPE_OFFSCREEN_BOX, GocOffscreenBoxClass))
+#define GOC_IS_OFFSCREEN_BOX(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOC_TYPE_OFFSCREEN_BOX))
+#define GOC_IS_OFFSCREEN_BOX_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GOC_TYPE_OFFSCREEN_BOX))
+#define GOC_OFFSCREEN_BOX_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GOC_TYPE_OFFSCREEN_BOX, GocOffscreenBoxClass))
+
+typedef struct _GocOffscreenBox	  GocOffscreenBox;
+typedef GtkBinClass  GocOffscreenBoxClass;
+
+static GObjectClass *goc_offscreen_box_parent_class;
+
+struct _GocOffscreenBox
+{
+	GtkBin base;
+	GtkWidget *child;
+	GdkWindow *offscreen_window;
+	gdouble angle, scale;
+};
+
+struct _GocOffscreenBoxClass
+{
+	GtkBinClass parent_class;
+};
+
+GType	   goc_offscreen_box_get_type  (void) G_GNUC_CONST;
+
+static void
+to_child (GocOffscreenBox *offscreen_box,
+          double widget_x, double widget_y,
+          double *x_out, double *y_out)
+{
+/*	GtkAllocation child_area;*/
+	double x, y/*, xr, yr*/;
+/*	double cos_angle, sin_angle;*/
+
+	x = widget_x;
+	y = widget_y;
+
+#if 0
+	/* rotation not supported for now */
+	if (offscreen_box->child && gtk_widget_get_visible (offscreen_box->child)) {
+		gtk_widget_get_allocation (offscreen_box->child, &child_area);
+		y -= child_area.height;
+	}
+
+	gtk_widget_get_allocation (offscreen_box->child2, &child_area);
+
+	x -= child_area.width / 2;
+	y -= child_area.height / 2;
+
+	cos_angle = cos (-offscreen_box->angle);
+	sin_angle = sin (-offscreen_box->angle);
+
+	xr = x * cos_angle - y * sin_angle;
+	yr = x * sin_angle + y * cos_angle;
+	x = xr;
+	y = yr;
+
+	x += child_area.width / 2;
+	y += child_area.height / 2;
+#endif
+
+	*x_out = x / offscreen_box->scale;
+	*y_out = y / offscreen_box->scale;
+}
+
+static void
+to_parent (GocOffscreenBox *offscreen_box,
+	     double offscreen_x, double offscreen_y,
+	     double *x_out, double *y_out)
+{
+/*  GtkAllocation child_area;*/
+	double x, y/*, xr, yr*/;
+/*  double cos_angle, sin_angle;*/
+
+/*  gtk_widget_get_allocation (offscreen_box->child2, &child_area);*/
+
+	x = offscreen_x * offscreen_box->scale;
+	y = offscreen_y * offscreen_box->scale;
+
+/*  x -= child_area.width / 2;
+  y -= child_area.height / 2;
+
+  cos_angle = cos (offscreen_box->angle);
+  sin_angle = sin (offscreen_box->angle);
+
+  xr = x * cos_angle - y * sin_angle;
+  yr = x * sin_angle + y * cos_angle;
+  x = xr;
+  y = yr;
+
+  x += child_area.width / 2;
+  y += child_area.height / 2;
+
+  if (offscreen_box->child1 && gtk_widget_get_visible (offscreen_box->child1))
+    {
+      gtk_widget_get_allocation (offscreen_box->child1, &child_area);
+      y += child_area.height;
+    }*/
+
+	*x_out = x;
+	*y_out = y;
+}
+
+static void
+offscreen_window_to_parent (GdkWindow       *offscreen_window,
+			    double           offscreen_x,
+			    double           offscreen_y,
+			    double          *parent_x,
+			    double          *parent_y,
+			    GocOffscreenBox *offscreen_box)
+{
+	to_parent (offscreen_box, offscreen_x, offscreen_y, parent_x, parent_y);
+}
+
+static void
+offscreen_window_from_parent (GdkWindow       *window,
+			      double           parent_x,
+			      double           parent_y,
+			      double          *offscreen_x,
+			      double          *offscreen_y,
+			      GocOffscreenBox *offscreen_box)
+{
+	to_child (offscreen_box, parent_x, parent_y, offscreen_x, offscreen_y);
+}
+
+static GdkWindow *
+pick_offscreen_child (GdkWindow *offscreen_window,
+		      double widget_x, double widget_y,
+		      GocOffscreenBox *offscreen_box)
+{
+	GtkAllocation child_area;
+	double x, y;
+
+	/* Check for child */
+	if (offscreen_box->child &&
+	    gtk_widget_get_visible (offscreen_box->child)) {
+		to_child (offscreen_box, widget_x, widget_y, &x, &y);
+
+		gtk_widget_get_allocation (offscreen_box->child, &child_area);
+
+		if (x >= 0 && x < child_area.width &&
+		    y >= 0 && y < child_area.height)
+			return offscreen_box->offscreen_window;
+	}
+
+	return NULL;
+}
+
+static void
+goc_offscreen_box_realize (GtkWidget *widget)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (widget);
+	GtkAllocation allocation, child_area;
+	GtkStyleContext *context;
+	GdkWindow *window;
+	GdkWindowAttr attributes;
+	gint attributes_mask;
+
+	gtk_widget_set_realized (widget, TRUE);
+
+	gtk_widget_get_allocation (widget, &allocation);
+
+	attributes.x = allocation.x;
+	attributes.y = allocation.y;
+	attributes.width = allocation.width;
+	attributes.height = allocation.height;
+	attributes.window_type = GDK_WINDOW_CHILD;
+	attributes.event_mask = gtk_widget_get_events (widget)
+		| GDK_EXPOSURE_MASK
+		| GDK_POINTER_MOTION_MASK
+		| GDK_BUTTON_PRESS_MASK
+		| GDK_BUTTON_RELEASE_MASK
+		| GDK_SCROLL_MASK
+		| GDK_ENTER_NOTIFY_MASK
+		| GDK_LEAVE_NOTIFY_MASK;
+
+	attributes.visual = gtk_widget_get_visual (widget);
+	attributes.wclass = GDK_INPUT_OUTPUT;
+
+	attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
+
+	window = gdk_window_new (gtk_widget_get_parent_window (widget),
+	                         &attributes, attributes_mask);
+	gtk_widget_set_window (widget, window);
+	gdk_window_set_user_data (window, widget);
+
+	g_signal_connect (window, "pick-embedded-child",
+	                  G_CALLBACK (pick_offscreen_child), offscreen_box);
+
+	attributes.window_type = GDK_WINDOW_OFFSCREEN;
+
+	attributes.x = attributes.y = 0;
+	if (offscreen_box->child &&
+	    gtk_widget_get_visible (offscreen_box->child)) {
+		gtk_widget_get_allocation (offscreen_box->child, &child_area);
+
+		attributes.width = child_area.width;
+		attributes.height = child_area.height;
+	}
+	offscreen_box->offscreen_window = gdk_window_new (gtk_widget_get_root_window (widget),
+	                                                  &attributes, attributes_mask);
+	gdk_window_set_user_data (offscreen_box->offscreen_window, widget);
+	if (offscreen_box->child)
+		gtk_widget_set_parent_window (offscreen_box->child,
+		                              offscreen_box->offscreen_window);
+
+	gdk_offscreen_window_set_embedder (offscreen_box->offscreen_window,
+	                                   window);
+
+	g_signal_connect (offscreen_box->offscreen_window, "to-embedder",
+	                  G_CALLBACK (offscreen_window_to_parent), offscreen_box);
+	g_signal_connect (offscreen_box->offscreen_window, "from-embedder",
+	                  G_CALLBACK (offscreen_window_from_parent), offscreen_box);
+
+	context = gtk_widget_get_style_context (widget);
+	gtk_style_context_set_background (context, window);
+	gtk_style_context_set_background (context, offscreen_box->offscreen_window);
+
+	gdk_window_show (offscreen_box->offscreen_window);
+}
+
+static void
+goc_offscreen_box_unrealize (GtkWidget *widget)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (widget);
+
+	gdk_window_set_user_data (offscreen_box->offscreen_window, NULL);
+	gdk_window_destroy (offscreen_box->offscreen_window);
+	offscreen_box->offscreen_window = NULL;
+
+	GTK_WIDGET_CLASS (goc_offscreen_box_parent_class)->unrealize (widget);
+}
+
+static void
+goc_offscreen_box_size_request (GtkWidget      *widget,
+				GtkRequisition *requisition)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (widget);
+
+	if (offscreen_box->child
+	    && gtk_widget_get_visible (offscreen_box->child)) {
+		GtkRequisition child_requisition;
+
+		gtk_widget_get_preferred_size (offscreen_box->child,
+		                               &child_requisition, NULL);
+
+		requisition->width = offscreen_box->scale * child_requisition.width;
+		requisition->height = offscreen_box->scale * child_requisition.height;
+	}
+
+	/* FIXME: should we take rotation into account? Original code does not */
+}
+
+static void
+goc_offscreen_box_get_preferred_width (GtkWidget *widget,
+                                       gint      *minimum,
+                                       gint      *natural)
+{
+	GtkRequisition requisition;
+
+	goc_offscreen_box_size_request (widget, &requisition);
+
+	*minimum = *natural = requisition.width;
+}
+
+static void
+goc_offscreen_box_get_preferred_height (GtkWidget *widget,
+                                        gint      *minimum,
+                                        gint      *natural)
+{
+	GtkRequisition requisition;
+
+	goc_offscreen_box_size_request (widget, &requisition);
+
+	*minimum = *natural = requisition.height;
+}
+
+static void
+goc_offscreen_box_size_allocate (GtkWidget     *widget,
+				 GtkAllocation *allocation)
+{
+	GocOffscreenBox *offscreen_box;
+
+	offscreen_box = GOC_OFFSCREEN_BOX (widget);
+
+	gtk_widget_set_allocation (widget, allocation);
+
+	if (gtk_widget_get_realized (widget))
+		gdk_window_move_resize (gtk_widget_get_window (widget),
+		                        allocation->x,
+		                        allocation->y,
+		                        allocation->width,
+		                        allocation->height);
+
+
+	if (offscreen_box->child
+	    && gtk_widget_get_visible (offscreen_box->child)) {
+		GtkRequisition child_requisition;
+		GtkAllocation child_allocation;
+
+		gtk_widget_get_preferred_size (offscreen_box->child,
+				             &child_requisition, NULL);
+		child_allocation.x = 0;
+		child_allocation.y = 0;
+		child_allocation.width = child_requisition.width;
+		child_allocation.height = child_requisition.height;
+
+		if (gtk_widget_get_realized (widget))
+		gdk_window_move_resize (offscreen_box->offscreen_window,
+					child_allocation.x,
+				        child_allocation.y,
+					child_allocation.width,
+				        child_allocation.height);
+
+		gtk_widget_size_allocate (offscreen_box->child, &child_allocation);
+	}
+}
+
+static gboolean
+goc_offscreen_box_damage (GtkWidget      *widget,
+                          GdkEventExpose *event)
+{
+	gdk_window_invalidate_rect (gtk_widget_get_window (widget),
+	                            NULL, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+goc_offscreen_box_draw (GtkWidget *widget,
+                        cairo_t   *cr)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (widget);
+	GdkWindow *window;
+
+	window = gtk_widget_get_window (widget);
+	if (gtk_cairo_should_draw_window (cr, window)) {
+		cairo_surface_t *surface;
+
+		if (offscreen_box->child && gtk_widget_get_visible (offscreen_box->child)) {
+			surface = gdk_offscreen_window_get_surface (offscreen_box->offscreen_window);
+
+#if 0
+			gtk_widget_get_allocation (offscreen_box->child, &child_area);
+
+			/* transform */
+			cairo_translate (cr, child_area.width / 2, child_area.height / 2);
+			cairo_rotate (cr, offscreen_box->angle);
+			cairo_translate (cr, -child_area.width / 2, -child_area.height / 2);
+#endif
+			cairo_scale (cr, offscreen_box->scale, offscreen_box->scale);
+			cairo_set_source_surface (cr, surface, 0, 0);
+			cairo_paint (cr);
+		}
+
+	} else if (gtk_cairo_should_draw_window (cr, offscreen_box->offscreen_window)) {
+		gtk_render_background (gtk_widget_get_style_context (widget), cr,
+		                       0, 0,
+		                       gdk_window_get_width (offscreen_box->offscreen_window),
+		                       gdk_window_get_height (offscreen_box->offscreen_window));
+
+		if (offscreen_box->child)
+			gtk_container_propagate_draw (GTK_CONTAINER (widget),
+						      offscreen_box->child, cr);
+	}
+
+	return FALSE;
+}
+
+static void
+goc_offscreen_box_add (GtkContainer *container,
+		       GtkWidget    *widget)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (container);
+
+	if (!offscreen_box->child) {
+		((GtkContainerClass *) goc_offscreen_box_parent_class)->add (container, widget);
+		gtk_widget_set_parent_window (widget, offscreen_box->offscreen_window);
+		offscreen_box->child = widget;
+	}
+}
+
+static void
+goc_offscreen_box_remove (GtkContainer *container,
+			  GtkWidget    *widget)
+{
+	GocOffscreenBox *offscreen_box = GOC_OFFSCREEN_BOX (container);
+	gboolean was_visible;
+
+	was_visible = gtk_widget_get_visible (widget);
+
+	if (offscreen_box->child == widget) {
+		((GtkContainerClass *) goc_offscreen_box_parent_class)->remove (container, widget);
+
+		offscreen_box->child = NULL;
+
+		if (was_visible &&
+		    gtk_widget_get_visible (GTK_WIDGET (container)))
+			gtk_widget_queue_resize (GTK_WIDGET (container));
+	}
+}
+
+static void
+goc_offscreen_box_class_init (GocOffscreenBoxClass *klass)
+{
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+	GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+	goc_offscreen_box_parent_class = g_type_class_peek_parent (klass);
+
+	widget_class->realize = goc_offscreen_box_realize;
+	widget_class->unrealize = goc_offscreen_box_unrealize;
+	widget_class->get_preferred_width = goc_offscreen_box_get_preferred_width;
+	widget_class->get_preferred_height = goc_offscreen_box_get_preferred_height;
+	widget_class->size_allocate = goc_offscreen_box_size_allocate;
+	widget_class->draw = goc_offscreen_box_draw;
+
+	g_signal_override_class_closure (g_signal_lookup ("damage-event", GTK_TYPE_WIDGET),
+		           GOC_TYPE_OFFSCREEN_BOX,
+		           g_cclosure_new (G_CALLBACK (goc_offscreen_box_damage),
+		                           NULL, NULL));
+	container_class->add = goc_offscreen_box_add;
+	container_class->remove = goc_offscreen_box_remove;
+}
+
+static void
+goc_offscreen_box_init (GocOffscreenBox *offscreen_box)
+{
+	gtk_widget_set_has_window (GTK_WIDGET (offscreen_box), TRUE);
+}
+
+GSF_CLASS (GocOffscreenBox, goc_offscreen_box,
+	   goc_offscreen_box_class_init, goc_offscreen_box_init,
+	   GTK_TYPE_BIN)
+
+static void
+goc_offscreen_box_set_scale (GocOffscreenBox  *offscreen_box,
+			     gdouble           scale)
+{
+	g_return_if_fail (GOC_IS_OFFSCREEN_BOX (offscreen_box));
+
+	offscreen_box->scale = scale;
+	gtk_widget_queue_resize (GTK_WIDGET (offscreen_box));
+
+	/* TODO: Really needs to resent pointer events if over the scaled window */
+}
+
+/******************************************************************************
+ * end of copied code
+ ******************************************************************************/
+
 /**
  * SECTION:goc-widget
  * @short_description: Widgets.
@@ -78,39 +535,29 @@ goc_widget_update_bounds (GocItem *item)
 }
 
 static void
-cb_canvas_changed (GocWidget *item, G_GNUC_UNUSED GParamSpec *pspec,
-		   G_GNUC_UNUSED gpointer user)
-{
-	GtkWidget *parent, *w = item->widget;
-	GocItem *gitem = (GocItem *)item;
-
-	if (!w)
-		return;
-
-	parent = gtk_widget_get_parent (w);
-	if (parent == (GtkWidget *)gitem->canvas)
-		return;
-
-	g_object_ref (w);
-	if (parent)
-		gtk_container_remove (GTK_CONTAINER (parent), w);
-	if (gitem->canvas)
-		gtk_layout_put (GTK_LAYOUT (gitem->canvas), w,
-				item->x, item->y);
-	g_object_unref (w);
-}
-
-static void
 goc_widget_notify_scrolled (GocItem *item)
 {
 	GocGroup const *parent;
 	double x0, y0, x1, y1;
 	GocWidget *widget = GOC_WIDGET (item);
+	int w, h;
 
 	parent = item->parent;
 	if (!parent)
 		return;
 
+	gtk_widget_set_size_request (widget->widget, 1, 1);
+	gtk_widget_get_preferred_width (widget->widget, &w, NULL);
+	gtk_widget_get_preferred_height (widget->widget, &h, NULL);
+	if (w > widget-> w || h > widget->h) {
+		widget->scale = fmin (widget->w / w, widget->h / h);
+		if (widget->scale == 0)
+			widget->scale = 1.;
+		w = widget->w / widget->scale;
+		h = widget->h / widget->scale;
+	} else
+		widget->scale = 1.;
+	gtk_widget_set_size_request (widget->widget, widget->w / widget->scale, widget->h / widget->scale);
 	if (!item->cached_bounds) {
 		goc_widget_update_bounds (GOC_ITEM (item)); /* don't care about const */
 		item->cached_bounds = TRUE;
@@ -130,7 +577,9 @@ goc_widget_notify_scrolled (GocItem *item)
 	}
 	y0 = (y0 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
 	y1 = (y1 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
-	gtk_widget_set_size_request (widget->widget, x1 - x0, y1 - y0);
+	goc_offscreen_box_set_scale (GOC_OFFSCREEN_BOX (widget->ofbox),
+	                             item->canvas->pixels_per_unit * widget->scale);
+	gtk_widget_set_size_request (widget->ofbox, go_fake_floor (x1 - x0), go_fake_floor (y1 - y0));
 	/* ensure we don't wrap throught he infinite */
 	if (x0 < G_MININT)
 		x0 = G_MININT;
@@ -140,7 +589,31 @@ goc_widget_notify_scrolled (GocItem *item)
 		y0 = G_MININT;
 	else if (y1 > G_MAXINT)
 		y0 -= y1 - G_MAXINT;
-	gtk_layout_move (GTK_LAYOUT (item->canvas), widget->widget, x0, y0);
+	gtk_layout_move (GTK_LAYOUT (item->canvas), widget->ofbox, x0, y0);
+}
+
+static void
+cb_canvas_changed (GocWidget *item, G_GNUC_UNUSED GParamSpec *pspec,
+		   G_GNUC_UNUSED gpointer user)
+{
+	GtkWidget *parent, *w = item->ofbox;
+	GocItem *gitem = (GocItem *)item;
+
+	if (!w || !GTK_IS_WIDGET (w))
+		return;
+
+	parent = gtk_widget_get_parent (w);
+	if (parent == (GtkWidget *)gitem->canvas)
+		return;
+
+	g_object_ref (w);
+	if (parent)
+		gtk_container_remove (GTK_CONTAINER (parent), w);
+	if (gitem->canvas)
+		gtk_layout_put (GTK_LAYOUT (gitem->canvas), w,
+				item->x, item->y);
+	goc_widget_notify_scrolled (GOC_ITEM (item));
+	g_object_unref (w);
 }
 
 static void
@@ -149,34 +622,39 @@ goc_widget_set_widget (GocWidget *item, GtkWidget *widget)
 	if (widget == item->widget)
 		return;
 
-	if (item->widget) {
-		GtkWidget *parent = gtk_widget_get_parent (item->widget);
+	if (item->ofbox) {
+		GtkWidget *parent = gtk_widget_get_parent (item->ofbox);
 
 		g_signal_handlers_disconnect_by_func
-			(item->widget, G_CALLBACK (enter_notify_cb), item);
+			(item->ofbox, G_CALLBACK (enter_notify_cb), item);
 		g_signal_handlers_disconnect_by_func
-			(item->widget, G_CALLBACK (button_press_cb), item);
+			(item->ofbox, G_CALLBACK (button_press_cb), item);
 
 		if (parent)
 			gtk_container_remove (GTK_CONTAINER (parent),
-					      item->widget);
+					      item->ofbox);
 
+		g_object_unref (item->ofbox);
 		g_object_unref (item->widget);
 	}
 
 	item->widget = widget;
 
 	if (widget) {
-		g_object_ref (item->widget);
+		g_object_ref (widget);
 		gtk_widget_show (widget);
+		item->ofbox = GTK_WIDGET (g_object_new (GOC_TYPE_OFFSCREEN_BOX, NULL));
+		gtk_container_add (GTK_CONTAINER (item->ofbox), widget);
+		gtk_widget_show (item->ofbox);
+		g_object_ref (item->ofbox);
 		if (GOC_ITEM (item)->canvas)
 			gtk_layout_put (GTK_LAYOUT (GOC_ITEM (item)->canvas),
-					widget, item->x, item->y);
+					item->ofbox, item->x, item->y);
 		goc_widget_notify_scrolled (GOC_ITEM (item));
 		/* we need to propagate some signals to the parent item */
-		g_signal_connect (widget, "enter-notify-event",
+		g_signal_connect (item->ofbox, "enter-notify-event",
 				  G_CALLBACK (enter_notify_cb), item);
-		g_signal_connect (widget, "button-press-event",
+		g_signal_connect (item->ofbox, "button-press-event",
 				  G_CALLBACK (button_press_cb), item);
 	}
 }
@@ -275,19 +753,6 @@ goc_widget_distance (GocItem *item, double x, double y, GocItem **near_item)
 }
 
 static void
-goc_widget_draw (GocItem const *item, cairo_t *cr)
-{
-	GocWidget *widget = GOC_WIDGET (item);
-	int x, y;
-	gtk_container_child_get (GTK_CONTAINER (item->canvas), widget->widget,
-	                         "x", &x, "y", &y, NULL);
-	cairo_save (cr);
-	cairo_translate (cr, x, y);
-	gtk_widget_draw (widget->widget, cr);
-	cairo_restore (cr);
-}
-
-static void
 goc_widget_dispose (GObject *object)
 {
 	GocWidget *item = GOC_WIDGET (object);
@@ -348,7 +813,6 @@ goc_widget_class_init (GocItemClass *item_klass)
 			GSF_PARAM_STATIC | G_PARAM_READWRITE));
 
 	item_klass->distance = goc_widget_distance;
-	item_klass->draw = goc_widget_draw;
 	item_klass->update_bounds = goc_widget_update_bounds;
 	item_klass->notify_scrolled = goc_widget_notify_scrolled;
 }
diff --git a/goffice/canvas/goc-widget.h b/goffice/canvas/goc-widget.h
index 9488737..e3bde76 100644
--- a/goffice/canvas/goc-widget.h
+++ b/goffice/canvas/goc-widget.h
@@ -29,8 +29,10 @@ G_BEGIN_DECLS
 struct _GocWidget {
 	GocItem base;
 
+	/* private */
 	double x, y, w, h;
-	GtkWidget *widget;
+	GtkWidget *widget, *ofbox;
+	double scale, rotation; /* rotation is not in use for now */
 };
 
 typedef GocItemClass GocWidgetClass;
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 12429e3..5289734 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -399,7 +399,7 @@ map_discrete_calc_ticks (GogAxis *axis)
 					g_free (label);
 				} else {
 					double val = go_data_get_vector_value (axis->labels, index);
-					if (go_finite (val)) 
+					if (go_finite (val))
 						axis_format_value (axis, val, &ticks[j].str);
 					else {
 						label = go_data_get_vector_string (axis->labels, index);
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index 9f1e394..96e6bee 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -1135,7 +1135,7 @@ gog_renderer_draw_data_label (GogRenderer *rend, GogSeriesLabelElt const *elt,
 		rect.x = rect.y = 0;
 		pango_layout_get_size (layout, &iw, &ih);
 		rect.height = 1; /* only the width is important */
-		rect.width = (legend_style->interesting_fields & GO_STYLE_LINE)? 2 * ih: ih; 
+		rect.width = (legend_style->interesting_fields & GO_STYLE_LINE)? 2 * ih: ih;
 		attr = pango_attr_shape_new (&rect, &rect);
 		attr->start_index = elt->legend_pos;
 		attr->end_index = elt->legend_pos + 1;
diff --git a/goffice/graph/gog-series-labels.c b/goffice/graph/gog-series-labels.c
index 5d19cce..882ddb6 100644
--- a/goffice/graph/gog-series-labels.c
+++ b/goffice/graph/gog-series-labels.c
@@ -553,11 +553,11 @@ gog_series_labels_populate_editor (GogObject *gobj,
 		}
 		gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (state->avail_list), 1, GTK_SORT_ASCENDING);
 	}
-	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, GOG_DATASET (gobj), 0, 
+	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, GOG_DATASET (gobj), 0,
 	                                           GOG_IS_DATA_LABEL (gobj)? GOG_DATA_SCALAR: GOG_DATA_VECTOR));
 	gtk_widget_show (w);
 	gtk_grid_attach (GTK_GRID (labels_prefs), w, 2, 6, 3, 1);
-	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, GOG_DATASET (gobj), 1, 
+	w = GTK_WIDGET (gog_data_allocator_editor (dalloc, GOG_DATASET (gobj), 1,
 	                                           GOG_DATA_SCALAR));
 	gtk_widget_show (w);
 	gtk_grid_attach (GTK_GRID (labels_prefs), w, 2, 7, 3, 1);
diff --git a/goffice/graph/gog-smoothed-curve.c b/goffice/graph/gog-smoothed-curve.c
index a54db68..6986a43 100644
--- a/goffice/graph/gog-smoothed-curve.c
+++ b/goffice/graph/gog-smoothed-curve.c
@@ -148,7 +148,7 @@ GSF_CLASS_FULL (GogSmoothedCurve, gog_smoothed_curve,
 	   NULL, NULL, gog_smoothed_curve_class_init, NULL,
            gog_smoothed_curve_init, GOG_TYPE_TREND_LINE, G_TYPE_FLAG_ABSTRACT,
 	   GSF_INTERFACE (gog_smoothed_curve_dataset_init, GOG_TYPE_DATASET))
- 
+
 /****************************************************************************/
 
 typedef GogView		GogSmoothedCurveView;
diff --git a/goffice/gtk/go-format-sel.c b/goffice/gtk/go-format-sel.c
index a18712e..28eaee7 100644
--- a/goffice/gtk/go-format-sel.c
+++ b/goffice/gtk/go-format-sel.c
@@ -341,7 +341,7 @@ load_si_combo (GtkWidget *w, GOFormatSel *gfs)
 	GtkCellRenderer  *cell;
 
 	for (i = 0; i < G_N_ELEMENTS (si_units); i++)
-		gtk_list_store_insert_with_values 
+		gtk_list_store_insert_with_values
 			(store, NULL, i,
 			 0, _(si_units[i].name),
 			 1, si_units[i].unit,
@@ -349,7 +349,7 @@ load_si_combo (GtkWidget *w, GOFormatSel *gfs)
 			 -1);
 	cell = gtk_cell_renderer_text_new();
 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(c), cell, TRUE);
-	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(c), cell, "text", 
+	gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(c), cell, "text",
 				       0, NULL);
 	gtk_combo_box_set_id_column (c, 1);
 }
@@ -540,9 +540,9 @@ cb_fraction_automatic_toggle (GtkWidget *w, GOFormatSel *gfs)
 {
 	gboolean act =gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w));
 	gfs->format.details.automatic_denominator = act;
-	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS_LABEL], 
+	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS_LABEL],
 				  act);
-	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS_LABEL], 
+	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS_LABEL],
 				  act);
 	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS], act);
 	gtk_widget_set_sensitive (gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS], act);
@@ -878,12 +878,12 @@ stays:
 		case F_EXP_DIGITS:
 			if (page == GO_FORMAT_FRACTION) {
 				gtk_spin_button_set_range (GTK_SPIN_BUTTON (w), 0, 30);
-				gtk_spin_button_set_value 
+				gtk_spin_button_set_value
 					(GTK_SPIN_BUTTON (w),
 					 gfs->format.details.numerator_min_digits);
 			} else {
 				gtk_spin_button_set_range (GTK_SPIN_BUTTON (w), 1, 10);
-				gtk_spin_button_set_value 
+				gtk_spin_button_set_value
 					(GTK_SPIN_BUTTON (w),
 					 gfs->format.details.exponent_digits);
 			}
@@ -891,11 +891,11 @@ stays:
 
 		case F_SI_BUTTON:
 #ifdef ALLOW_SI_APPEND
-			gtk_toggle_button_set_active 
+			gtk_toggle_button_set_active
 				(GTK_TOGGLE_BUTTON (w),
 				 gfs->format.details.append_SI);
 #else
-			gtk_toggle_button_set_active 
+			gtk_toggle_button_set_active
 				(GTK_TOGGLE_BUTTON (w), FALSE);
 			show_widget = FALSE;
 #endif
@@ -926,43 +926,43 @@ stays:
 				char const *unit = gfs->format.details.appended_SI_unit;
 				if (unit[0] == 'g' && unit[1] == 0)
 					unit = "kg";
-				for (ii = 0; ii < G_N_ELEMENTS (si_units); ii++) 
+				for (ii = 0; ii < G_N_ELEMENTS (si_units); ii++)
 					if (0 == strcmp (si_units[ii].unit, unit)) {
 						row = (gint)ii;
 						break;
 					}
 			}
-					
+
 			if (row == -1) {
 				if (gfs->format.details.appended_SI_unit == NULL) {
-					gtk_button_set_label 
+					gtk_button_set_label
 						(GTK_BUTTON (gfs->format.widget[F_SI_CUSTOM_UNIT_BUTTON]),
 						 _("Append no further unit."));
 					g_free (gfs->format.default_si_unit);
 					gfs->format.default_si_unit = NULL;
 				} else {
 					gchar *label;
-					gfs->format.default_si_unit 
+					gfs->format.default_si_unit
 						= g_strdup (gfs->format.details.appended_SI_unit);
-					label = g_strdup_printf (_("Append \'%s\'."), 
+					label = g_strdup_printf (_("Append \'%s\'."),
 								 gfs->format.default_si_unit);
-					gtk_button_set_label 
+					gtk_button_set_label
 						(GTK_BUTTON (gfs->format.widget[F_SI_CUSTOM_UNIT_BUTTON]),
 						 label);
 					g_free (label);
 				}
 			} else
 				gtk_combo_box_set_active_id (GTK_COMBO_BOX (w), si_units[row].unit);
-			
+
 			if (row >= 0)
-				gtk_toggle_button_set_active 
+				gtk_toggle_button_set_active
 					(GTK_TOGGLE_BUTTON (gfs->format.widget[F_SI_SI_UNIT_BUTTON]),
 					 TRUE);
 			else
-				gtk_toggle_button_set_active 
+				gtk_toggle_button_set_active
 					(GTK_TOGGLE_BUTTON (gfs->format.widget[F_SI_CUSTOM_UNIT_BUTTON]),
 					 TRUE);
-				
+
 
 #else
 				show_widget = FALSE;
@@ -977,64 +977,64 @@ stays:
 			break;
 
 		case F_SEPARATOR:
-			gtk_toggle_button_set_active 
+			gtk_toggle_button_set_active
 				(GTK_TOGGLE_BUTTON (w),
 				 gfs->format.details.thousands_sep);
 			break;
 
 		case F_FRACTION_SEPARATE_INTEGER:
-			gtk_toggle_button_set_active 
+			gtk_toggle_button_set_active
 				(GTK_TOGGLE_BUTTON (w),
 				 gfs->format.details.split_fraction);
 			break;
 
 		case F_FRACTION_MIN_INTEGER_DIGITS:
-			gtk_spin_button_set_value 
-				(GTK_SPIN_BUTTON (w), 
+			gtk_spin_button_set_value
+				(GTK_SPIN_BUTTON (w),
 				 gfs->format.details.min_digits);
-			gtk_widget_set_sensitive 
+			gtk_widget_set_sensitive
 				(w, gfs->format.details.split_fraction);
-			gtk_widget_set_sensitive 
-				(gfs->format.widget[F_FRACTION_MIN_INTEGER_DIGITS_LABEL], 
+			gtk_widget_set_sensitive
+				(gfs->format.widget[F_FRACTION_MIN_INTEGER_DIGITS_LABEL],
 				 gfs->format.details.split_fraction);
 			break;
 
 		case F_FRACTION_AUTOMATIC:
-			gtk_toggle_button_set_active 
+			gtk_toggle_button_set_active
 				(GTK_TOGGLE_BUTTON (w),
 				 gfs->format.details.automatic_denominator);
 			break;
 
 		case F_FRACTION_DENOMINATOR:
-			gtk_spin_button_set_value 
+			gtk_spin_button_set_value
 				(GTK_SPIN_BUTTON (w),
 				 gfs->format.details.denominator);
-			gtk_widget_set_sensitive 
+			gtk_widget_set_sensitive
 				(w, !gfs->format.details.automatic_denominator);
-			gtk_widget_set_sensitive 
-				(gfs->format.widget[F_FRACTION_DENOMINATOR_LABEL], 
+			gtk_widget_set_sensitive
+				(gfs->format.widget[F_FRACTION_DENOMINATOR_LABEL],
 				 !gfs->format.details.automatic_denominator);
 			break;
 
 		case F_FRACTION_MAX_DENOM_DIGITS:
-			gtk_spin_button_set_value 
+			gtk_spin_button_set_value
 				(GTK_SPIN_BUTTON (w),
 				 gfs->format.details.denominator_max_digits);
-			gtk_widget_set_sensitive 
+			gtk_widget_set_sensitive
 				(w, gfs->format.details.automatic_denominator);
-			gtk_widget_set_sensitive 
-				(gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS_LABEL], 
+			gtk_widget_set_sensitive
+				(gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS_LABEL],
 				 gfs->format.details.automatic_denominator);
 			break;
 
 		case F_FRACTION_MIN_DENOM_DIGITS:
-			gtk_spin_button_set_value 
+			gtk_spin_button_set_value
 				(GTK_SPIN_BUTTON (w),
 				 gfs->format.details.denominator_min_digits);
-			gtk_widget_set_sensitive 
+			gtk_widget_set_sensitive
 				(w, gfs->format.details.automatic_denominator);
-			gtk_widget_set_sensitive 
-				(gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS_LABEL], 
+			gtk_widget_set_sensitive
+				(gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS_LABEL],
 				 gfs->format.details.automatic_denominator);
 			break;
 
@@ -1044,7 +1044,7 @@ stays:
 				(GTK_TOGGLE_BUTTON (w),
 				 gfs->format.details.pi_scale);
 #else
-				(GTK_TOGGLE_BUTTON (w), FALSE);			
+				(GTK_TOGGLE_BUTTON (w), FALSE);
 #endif
 			break;
 
@@ -1249,7 +1249,7 @@ study_format (GOFormat const *fmt, GOFormatDetails *details)
 		    !details->thousands_sep)
 			exact = FALSE;
 
-		if ((details->family != GO_FORMAT_FRACTION) 
+		if ((details->family != GO_FORMAT_FRACTION)
 		    && (details->min_digits > 1))
 			exact = FALSE;
 	}
@@ -1503,33 +1503,33 @@ nfs_init (GOFormatSel *gfs)
 		G_CALLBACK (cb_superscript_toggle), gfs);
 	g_signal_connect (G_OBJECT (gfs->format.widget[F_SI_BUTTON]), "toggled",
 		G_CALLBACK (cb_si_toggle), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_SI_SI_UNIT_BUTTON]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_SI_SI_UNIT_BUTTON]),
 			  "toggled", G_CALLBACK (cb_si_unit_toggle), gfs);
 	load_si_combo (gfs->format.widget[F_SI_UNIT_COMBO], gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_SI_UNIT_COMBO]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_SI_UNIT_COMBO]),
 			  "changed", G_CALLBACK (cb_si_combo_changed), gfs);
-	
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_SUPERSCRIPT_HIDE_1_BUTTON]), 
+
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_SUPERSCRIPT_HIDE_1_BUTTON]),
 			  "toggled", G_CALLBACK (cb_superscript_hide_1_toggle), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_AUTOMATIC]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_AUTOMATIC]),
 			  "toggled", G_CALLBACK (cb_fraction_automatic_toggle), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_SEPARATE_INTEGER]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_SEPARATE_INTEGER]),
 			  "toggled", G_CALLBACK (cb_split_fraction_toggle), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_PI_SCALE]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_PI_SCALE]),
 			  "toggled",
-			  G_CALLBACK (cb_pi_scale_toggle), gfs);	
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MIN_INTEGER_DIGITS]), 
+			  G_CALLBACK (cb_pi_scale_toggle), gfs);
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MIN_INTEGER_DIGITS]),
 			  "value_changed",
 			  G_CALLBACK (cb_min_integer_digits_changed), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_DENOMINATOR]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_DENOMINATOR]),
 			  "value_changed",
 			  G_CALLBACK (cb_denominator_changed), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MAX_DENOM_DIGITS]),
 			  "value_changed",
 			  G_CALLBACK (cb_max_denom_digits_changed), gfs);
-	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS]), 
+	g_signal_connect (G_OBJECT (gfs->format.widget[F_FRACTION_MIN_DENOM_DIGITS]),
 			  "value_changed",
-			  G_CALLBACK (cb_min_denom_digits_changed), gfs);	
+			  G_CALLBACK (cb_min_denom_digits_changed), gfs);
 
 	/* setup custom format list */
 	gfs->format.formats.model = gtk_list_store_new (1, G_TYPE_STRING);
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index 0618afe..d3d3c84 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -905,13 +905,13 @@ go_format_token2 (char const **pstr, GOFormatTokenType *ptt, gboolean localized)
 		if (str[1] == 'S' && str[2] == 'I') {
 			t = TOK_EXP_SI,
 			len = 3;
-		} else 
+		} else
 #endif
 #if defined(ALLOW_EE_MARKUP) && defined(ALLOW_SI_APPEND)
 		if (str[1] == 'E' && str[2] == 'S' && str[3] == 'I') {
 			t = TOK_EXP_MU_SI;
 			len = 4;
-		} else 
+		} else
 #endif
 #ifdef ALLOW_EE_MARKUP
 	        if (str[1] == 'E') {
@@ -1612,7 +1612,7 @@ go_format_parse_number_new_1 (GString *prg, GOFormatParseState *pstate,
 			whole_part = FALSE;
 			break;
 
-		case '0': 
+		case '0':
 			inhibit_b = TRUE;
 			/* no break */
 		case '?': case '#':
@@ -1628,7 +1628,7 @@ go_format_parse_number_new_1 (GString *prg, GOFormatParseState *pstate,
 			if (E_part != 1 && E_part != 2)
  				scale += 2;
  			break;
- 
+
 		case '\'':
 			if (E_part == 1)
 				scale += 3;
@@ -2056,7 +2056,7 @@ go_format_parse_number_fraction (GOFormatParseState *pstate)
 						   0, 1, &inhibit_blank_whole))
 			return NULL;
 		scale += pstate->scale;
-		
+
 		if (pi_scale) {
 			/* ADD_OPuc (OP_CHAR, UNICODE_THINSPACE); */
 			ADD_OPuc (OP_CHAR, UNICODE_PI); /* "pi" */
@@ -2099,7 +2099,7 @@ go_format_parse_number_fraction (GOFormatParseState *pstate)
 			ADD_OP (OP_NUM_FRACTION_SIMPLIFY_PI);
 		if (!inhibit_blank_numerator)
 			ADD_OP (OP_NUM_FRACTION_SIMPLIFY_NUMERATOR_PI);
-		
+
 	} else
 #endif
 		{
@@ -2108,7 +2108,7 @@ go_format_parse_number_fraction (GOFormatParseState *pstate)
 			if (!inhibit_blank_denom)
 				ADD_OP (OP_NUM_FRACTION_SIMPLIFY);
 			if (!inhibit_blank_numerator)
-				ADD_OP (OP_NUM_FRACTION_SIMPLIFY_NUMERATOR);			
+				ADD_OP (OP_NUM_FRACTION_SIMPLIFY_NUMERATOR);
 		}
 	if (!inhibit_blank_whole)
 		ADD_OP (OP_NUM_FRACTION_BLANK_WHOLE);
@@ -2613,23 +2613,23 @@ SUFFIX(printf_engineering) (GString *dst, DOUBLE val, int n, int wd)
 
 #ifdef DEFINE_COMMON
 static int
-go_format_get_width (GString *dst, PangoAttrList *attrs, int start, 
+go_format_get_width (GString *dst, PangoAttrList *attrs, int start,
 		     int length, PangoLayout *layout)
 {
 	GList *plist, *l;
 	PangoContext *context;
 	int width = 0;
 
-	if (layout == NULL || 
-	    (context = pango_layout_get_context (layout)) == NULL 
+	if (layout == NULL ||
+	    (context = pango_layout_get_context (layout)) == NULL
 	    || pango_context_get_font_map (context) == NULL)
 		return 0;
-	
+
 	plist = pango_itemize (context, dst->str, start, length, attrs, NULL);
 	for (l = plist; l != NULL; l = l->next) {
 		PangoItem *pi = l->data;
 		PangoGlyphString *glyphs = pango_glyph_string_new ();
-		
+
 		pango_shape (dst->str + pi->offset, pi->length, &pi->analysis, glyphs);
 		width += pango_glyph_string_get_width (glyphs);
 		pango_glyph_string_free (glyphs);
@@ -2649,8 +2649,8 @@ go_format_desired_width (PangoLayout *layout, PangoAttrList *attrs, int digits)
 	int width = 0;
 	PangoContext *context;
 
-	if (layout == NULL || 
-	    (context = pango_layout_get_context (layout)) == NULL 
+	if (layout == NULL ||
+	    (context = pango_layout_get_context (layout)) == NULL
 	    || pango_context_get_font_map (context) == NULL)
 		return 0;
 
@@ -2660,7 +2660,7 @@ go_format_desired_width (PangoLayout *layout, PangoAttrList *attrs, int digits)
 		PangoGlyphString *glyphs = pango_glyph_string_new ();
 		PangoRectangle ink_rect;
 		PangoRectangle logical_rect;
-		
+
 		pango_shape (strp + pi->offset, pi->length, &pi->analysis, glyphs);
 		pango_glyph_string_extents (glyphs,
 					    pi->analysis.font,
@@ -2670,7 +2670,7 @@ go_format_desired_width (PangoLayout *layout, PangoAttrList *attrs, int digits)
 		width += logical_rect.width;
 	}
 	go_list_free_custom (plist, (GFreeFunc) pango_item_free);
-	
+
 	return (int)(1.1 * width *digits);
 }
 #endif
@@ -2678,7 +2678,7 @@ go_format_desired_width (PangoLayout *layout, PangoAttrList *attrs, int digits)
 
 #ifdef DEFINE_COMMON
 static void
-blank_characters (GString *dst, PangoAttrList *attrs, int start, int length, 
+blank_characters (GString *dst, PangoAttrList *attrs, int start, int length,
 		  PangoLayout *layout)
 {
 	/* We have layouts that have no fontmap set, we need to avoid them */
@@ -2755,11 +2755,11 @@ si_reduction (int exponent, char const **si)
 		{"y" ,-24}
 	};
 	guint i;
-	
+
 	for (i = 0; i < G_N_ELEMENTS (si_prefixes) - 1; i++)
 		if (si_prefixes[i].power <= exponent)
 			break;
-	
+
 	*si = si_prefixes[i].prefix;
 	return si_prefixes[i].power;
 }
@@ -3280,7 +3280,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 		case OP_NUM_MOVETO_ONES: {
 			numi = dotpos;
 			/* Ignore the zero in "0.xxx" or "0 xx/xx" */
-			if (numi == 1 && numtxt->str[0] == '0' && 
+			if (numi == 1 && numtxt->str[0] == '0' &&
 			    numtxt->str[dotpos] != 0)
 				numi--;
 			numpos = dst->len;
@@ -3309,7 +3309,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				g_string_insert_c (dst, numpos, c);
 				if (numpos_end >= 0)
 					numpos_end++;
-				
+
 			}
 			break;
 
@@ -3420,7 +3420,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 
 		case OP_NUM_SIMPLIFY_MARKUP_MANTISSA:
 			if (special_mantissa == 0) {
-				g_string_erase (dst, mantissa_start, 
+				g_string_erase (dst, mantissa_start,
 						numpos_end - mantissa_start);
 				g_string_insert_c (dst, mantissa_start, '0');
 				numpos_end = mantissa_start + 1;
@@ -3460,7 +3460,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				g_string_truncate (dst, mantissa_start);
 				si_pos = mantissa_start;
 			}
-			
+
 			break;
 
 		case OP_NUM_REDUCE_EXPONENT_SI:
@@ -3542,7 +3542,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			val = fraction.n;
 			break;
 
-		case OP_NUM_FRACTION_SLASH: 
+		case OP_NUM_FRACTION_SLASH:
 			{
 				int desired_width = go_format_desired_width (layout, attrs, fraction.digits);
 				int length;
@@ -3553,10 +3553,10 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				while (!g_unichar_isdigit (g_utf8_get_char (end)) && end > nom)
 					end = g_utf8_prev_char (end);
 				end = g_utf8_find_next_char (end, NULL);
-				length = end - nom; 
+				length = end - nom;
 
-				logical_rect.width = go_format_get_width 
-					(dst, attrs, fraction.nominator_start, 
+				logical_rect.width = go_format_get_width
+					(dst, attrs, fraction.nominator_start,
 					 length, layout);
 
 				if (logical_rect.width < desired_width) {
@@ -3584,7 +3584,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			if (fraction.n == 0) {
 				/* Replace all added characters by spaces of the right length.  */
 				if (dst->len > fraction.nominator_start) {
-					blank_characters (dst, attrs, fraction.nominator_start, 
+					blank_characters (dst, attrs, fraction.nominator_start,
 							  dst->len - fraction.nominator_start, layout);
 					fraction.blanked = TRUE;
 				}
@@ -3606,7 +3606,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			}
 			break;
 
-		case OP_NUM_FRACTION_BLANK_WHOLE: 
+		case OP_NUM_FRACTION_BLANK_WHOLE:
 			if (!fraction.blanked && fraction.w == 0) {
 				gsize start = fraction.whole_start;
 				gsize length = fraction.nominator_start - start;
@@ -3618,23 +3618,23 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			} else if (fraction.pi_sum_start > 0) {
 				if (fraction.w == 1) {
 					gsize start = fraction.whole_start;
-					gsize length = fraction.pi_sum_start 
+					gsize length = fraction.pi_sum_start
 						- UNICODE_PI_number_of_bytes - start;
 					g_string_erase (dst, start, length);
 					go_pango_attr_list_erase (attrs, start, length);
 					fraction.nominator_start -= length;
 					fraction.denominator_start -= length;
-					fraction.pi_sum_start = 0;				
+					fraction.pi_sum_start = 0;
 				} else if (fraction.w == 0) {
-					blank_characters 
-						(dst, attrs, 
-						 fraction.pi_sum_start - UNICODE_PI_number_of_bytes, 
+					blank_characters
+						(dst, attrs,
+						 fraction.pi_sum_start - UNICODE_PI_number_of_bytes,
 						 UNICODE_PI_number_of_bytes, layout);
 				}
 			}
 			break;
 
-		case OP_NUM_FRACTION_ALIGN: 
+		case OP_NUM_FRACTION_ALIGN:
 			if (layout && pango_context_get_font_map (pango_layout_get_context (layout))) {
 				int desired_width = go_format_desired_width (layout, attrs, fraction.digits);
 				PangoRectangle logical_rect = {0, 0, 0, 2 * PANGO_SCALE};
@@ -3656,7 +3656,7 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 			}
 			break;
 
-			
+
 #ifdef ALLOW_PI_SLASH
 		case OP_NUM_FRACTION_SIMPLIFY_PI:
 #endif
@@ -5681,7 +5681,7 @@ go_format_generate_fraction_str (GString *dst, GOFormatDetails const *details)
 	int denominator_min_digits = CLAMP (details->denominator_min_digits, 0, denominator_max_digits);
 	int denominator = CLAMP (details->denominator, 2, G_MAXINT);
 	int num_digits;
-	
+
 	if (details->split_fraction) {
 		/* Maximum not terribly important. */
 		int min_digits = CLAMP (details->min_digits, 0, 30);
@@ -5696,7 +5696,7 @@ go_format_generate_fraction_str (GString *dst, GOFormatDetails const *details)
 		num_digits = denominator_max_digits - numerator_min_digits;
 	else
 		num_digits = cnt_digits (denominator) - numerator_min_digits;
-	
+
 	if (num_digits > 0)
 		go_string_append_c_n (dst, '?', num_digits);
 	if  (numerator_min_digits > 0)
@@ -5706,14 +5706,14 @@ go_format_generate_fraction_str (GString *dst, GOFormatDetails const *details)
 		g_string_append (dst, " pi/");
 	else
 		g_string_append_c (dst, '/');
-	
+
 	if (details->automatic_denominator) {
-		go_string_append_c_n (dst, '?', 
+		go_string_append_c_n (dst, '?',
 				      denominator_max_digits - denominator_min_digits);
-		go_string_append_c_n (dst, '0', 
+		go_string_append_c_n (dst, '0',
 				      denominator_min_digits);
 	} else
-		g_string_append_printf (dst, "%d", denominator); 
+		g_string_append_printf (dst, "%d", denominator);
 }
 #endif
 
@@ -6161,7 +6161,7 @@ go_format_get_details (GOFormat const *fmt,
 			numerator_base = 1;
 		} else
 			numerator_base = 0;
-		
+
 		integer = tokens[numerator_base];
 		dst->numerator_min_digits = 0;
 		while (*integer != 0)
@@ -6178,8 +6178,8 @@ go_format_get_details (GOFormat const *fmt,
 			dst->denominator_min_digits = 0;
 			dst->denominator_max_digits = 0;
 			while (*integer != 0) {
-				if (*integer == '#' || *integer == '?' 
-				    || g_ascii_isdigit (*integer)) 
+				if (*integer == '#' || *integer == '?'
+				    || g_ascii_isdigit (*integer))
 					dst->denominator_max_digits++;
 				if (*integer == '0') {
 					dst->denominator_min_digits++;
@@ -6188,7 +6188,7 @@ go_format_get_details (GOFormat const *fmt,
 			}
 		}
 
-		g_strfreev (tokens);	
+		g_strfreev (tokens);
 		g_free (c_str);
 
 		if (exact != NULL) {
diff --git a/goffice/utils/go-string.c b/goffice/utils/go-string.c
index 3d781b0..5048bd1 100644
--- a/goffice/utils/go-string.c
+++ b/goffice/utils/go-string.c
@@ -674,11 +674,11 @@ go_string_trim (GOString *gstr, gboolean internal)
 
 	if ((impl->flags & GO_STRING_IS_RICH) == 0)
 		return gstr;
-	
+
 	attrs = go_string_get_markup (gstr);
 	t = ctext = text = g_strdup (gstr->str);
 	if (attrs != NULL)
-		attrs = pango_attr_list_copy (attrs);		
+		attrs = pango_attr_list_copy (attrs);
 	while (*t != 0 && *t == ' ')
 		t++;
 	cnt = t - text;
diff --git a/plugins/plot_xy/gog-xy.c b/plugins/plot_xy/gog-xy.c
index 69995d2..eb9e25f 100644
--- a/plugins/plot_xy/gog-xy.c
+++ b/plugins/plot_xy/gog-xy.c
@@ -1512,7 +1512,7 @@ gog_xy_view_render (GogView *view, GogViewAllocation const *bbox)
 		if (style->interesting_fields & GO_STYLE_MARKER)
 			msize = (double) go_marker_get_size (style->marker.mark)
 				/ 2. * gog_renderer_get_scale (view->renderer);
-		else 
+		else
 			msize = style->line.width / .7;
 
 		if (!gog_series_is_valid (GOG_SERIES (series)))
@@ -1629,7 +1629,7 @@ gog_xy_view_render (GogView *view, GogViewAllocation const *bbox)
 		}
 		g_slist_free (labels);
 	}
-	
+
 	/* Now render children, may be should come before markers? */
 	for (ptr = view->children ; ptr != NULL ; ptr = ptr->next)
 		gog_view_render	(ptr->data, bbox);



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