[gnome-system-tools/rendering-cleanup: 9/21] e-map: Make cache a server-side surface



commit ce7c968fe97fe78ef1a1b7cca7a8c0a50e9888a7
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 4 19:04:11 2010 +0200

    e-map: Make cache a server-side surface
    
    Doing performance optimizations on the client is not a good idea...

 src/time/e-map/e-map.c |  180 ++++++++++++++++++++++--------------------------
 1 files changed, 82 insertions(+), 98 deletions(-)
---
diff --git a/src/time/e-map/e-map.c b/src/time/e-map/e-map.c
index 4597b7a..d88c970 100644
--- a/src/time/e-map/e-map.c
+++ b/src/time/e-map/e-map.c
@@ -56,7 +56,8 @@ EMapZoomState;
 
 struct _EMapPrivate {
 	/* Pointer to map image */
-	GdkPixbuf *map_pixbuf, *map_render_pixbuf;
+	GdkPixbuf *map_pixbuf;
+        cairo_surface_t *map_render_surface;
 
 	/* Settings */
 	gboolean frozen, smooth_zoom;
@@ -94,7 +95,7 @@ static gint e_map_expose (GtkWidget *widget, GdkEventExpose *event);
 static gint e_map_key_press (GtkWidget *widget, GdkEventKey *event);
 static void e_map_set_scroll_adjustments (GtkWidget *widget, GtkAdjustment *hadj, GtkAdjustment *vadj);
 
-static void update_render_pixbuf (EMap *map, GdkInterpType interp, gboolean render_overlays);
+static void update_render_surface (EMap *map, gboolean render_overlays);
 static void set_scroll_area (EMap *view, int width, int height);
 static void center_at (EMap *map, gint x, gint y);
 static void smooth_center_at (EMap *map, gint x, gint y);
@@ -259,11 +260,8 @@ e_map_finalize (GObject *object)
 		priv->map_pixbuf = NULL;
 	}
 
-	if (priv->map_render_pixbuf)
-	{
-		g_object_unref (priv->map_render_pixbuf);
-		priv->map_render_pixbuf = NULL;
-	}
+        /* gone in unrealize */
+        g_assert (priv->map_render_surface == NULL);
 
 	g_free (priv);
 	view->priv = NULL;
@@ -326,7 +324,7 @@ e_map_realize (GtkWidget *widget)
 	gtk_widget_set_style (widget, style);
 
 	gdk_window_set_back_pixmap (window, NULL, FALSE);
-	update_render_pixbuf (E_MAP (widget), GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (E_MAP (widget), TRUE);
 }
 
 /* Unrealize handler for the map view */
@@ -334,8 +332,11 @@ e_map_realize (GtkWidget *widget)
 static void
 e_map_unrealize (GtkWidget *widget)
 {
-	g_return_if_fail (widget != NULL);
-	g_return_if_fail (E_IS_MAP (widget));
+        EMap *view = E_MAP (widget);
+	EMapPrivate *priv = view->priv;
+
+        cairo_surface_destroy (priv->map_render_surface);
+        priv->map_render_surface = NULL;
 
 	if (GTK_WIDGET_CLASS (parent_class)->unrealize)
 		(*GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
@@ -391,7 +392,7 @@ e_map_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
                 gtk_widget_queue_draw (widget);
 	}
 
-	update_render_pixbuf (view, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (view, TRUE);
 }
 
 /* Button press handler for the map view */
@@ -448,16 +449,15 @@ e_map_expose (GtkWidget *widget, GdkEventExpose *event)
 
 	view = E_MAP (widget);
 	priv = view->priv;
-	if (!priv->map_render_pixbuf) return FALSE;
 
         cr = gdk_cairo_create (event->window);
         gdk_cairo_region (cr, event->region);
         cairo_clip (cr);
 
-        gdk_cairo_set_source_pixbuf (cr, 
-                                     priv->map_render_pixbuf,
-                                     - priv->xofs,
-                                     - priv->yofs);
+        cairo_set_source_surface (cr, 
+                                  priv->map_render_surface,
+                                  - priv->xofs,
+                                  - priv->yofs);
         cairo_paint (cr);
         
         cairo_destroy (cr);
@@ -641,8 +641,8 @@ e_map_window_to_world (EMap *map, gdouble win_x, gdouble win_y, gdouble *world_l
 	priv = map->priv;
 	g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (map)));
 
-	width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
-	height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
+	width = E_MAP_GET_WIDTH (map);
+	height = E_MAP_GET_HEIGHT (map);
 
 	*world_longitude = (win_x + priv->xofs - (gdouble) width / 2.0) /
 		((gdouble) width / 2.0) * 180.0;
@@ -659,12 +659,12 @@ e_map_world_to_window (EMap *map, gdouble world_longitude, gdouble world_latitud
 	g_return_if_fail (map);
 
 	priv = map->priv;
-	g_return_if_fail (priv->map_render_pixbuf);
+	g_return_if_fail (priv->map_render_surface);
 	g_return_if_fail (world_longitude >= -180.0 && world_longitude <= 180.0);
 	g_return_if_fail (world_latitude >= -90.0 && world_latitude <= 90.0);
 
-	width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
-	height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
+	width = E_MAP_GET_WIDTH (map);
+	height = E_MAP_GET_HEIGHT (map);
 
 	*win_x = (width / 2.0 + (width / 2.0) * world_longitude / 180.0) - priv->xofs;
 	*win_y = (height / 2.0 - (height / 2.0) * world_latitude / 90.0) - priv->yofs;
@@ -788,7 +788,7 @@ e_map_remove_point (EMap *map, EMapPoint *point)
 		/* FIXME: Re-scaling the whole pixbuf is more than a little
 		 * overkill when just one point is removed */
 
-		update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
+		update_render_surface (map, TRUE);
 		repaint_point (map, point);
 	}
 
@@ -848,7 +848,7 @@ e_map_point_is_in_view (EMap *map, EMapPoint *point)
 	gdouble x, y;
 
 	priv = map->priv;
-	if (!priv->map_render_pixbuf) return FALSE;
+	if (!priv->map_render_surface) return FALSE;
 
 	e_map_world_to_window (map, point->longitude, point->latitude, &x, &y);
 	gtk_widget_get_allocation (GTK_WIDGET (map), &allocation);
@@ -897,7 +897,7 @@ e_map_get_closest_point (EMap *map, gdouble longitude, gdouble latitude, gboolea
 static void
 update_and_paint (EMap *map)
 {
-	update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (map, TRUE);
 	gtk_widget_queue_draw (GTK_WIDGET (map));
 }
 
@@ -915,15 +915,14 @@ load_map_background (EMap *view, gchar *name)
 
 	if (priv->map_pixbuf) g_object_unref (priv->map_pixbuf);
 	priv->map_pixbuf = pb0;
-	update_render_pixbuf (view, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (view, TRUE);
 
 	return TRUE;
 }
 
 static void
-update_render_pixbuf (EMap *map,
-                      GdkInterpType interp,
-                      gboolean render_overlays)
+update_render_surface (EMap *map,
+                       gboolean render_overlays)
 {
 	EMapPrivate *priv;
 	EMapPoint *point;
@@ -959,20 +958,25 @@ update_render_pixbuf (EMap *map,
 
 	/* Reallocate the pixbuf */
 
-	if (priv->map_render_pixbuf) g_object_unref (priv->map_render_pixbuf);
-	priv->map_render_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE,	/* No alpha */
-						  8, width, height);
+	if (priv->map_render_surface) cairo_surface_destroy (priv->map_render_surface);
+	priv->map_render_surface = gdk_window_create_similar_surface (gtk_widget_get_window (GTK_WIDGET (map)),
+                                                                      CAIRO_CONTENT_COLOR,
+			         			              width, height);
 
 	/* Scale the original map into the rendering pixbuf */
-
 	if (width > 1 && height > 1)
 	{
-		gdk_pixbuf_scale (priv->map_pixbuf, priv->map_render_pixbuf, 0, 0,  /* Dest (x, y) */
-				  width, height, 0, 0,				    /* Offset (x, y) */
-				  zoom, zoom,					    /* Scale (x, y) */
-				  interp);
+                cairo_t *cr = cairo_create (priv->map_render_surface);
+                cairo_scale (cr, (double) width / orig_width, (double) height / orig_height);
+                gdk_cairo_set_source_pixbuf (cr, priv->map_pixbuf, 0, 0);
+                cairo_paint (cr);
+                cairo_destroy (cr);
 	}
 
+	/* Compute image offsets with respect to window */
+
+	set_scroll_area (map, width, height);
+
 	if (render_overlays)
 	{
 		/* Add points */
@@ -983,73 +987,53 @@ update_render_pixbuf (EMap *map,
 			update_render_point (map, point);
 		}
 	}
-
-	/* Compute image offsets with respect to window */
-
-	set_scroll_area (map, width, height);
-}
-
-/* Queues a repaint of the specified area in window coordinates */
-
-static void
-put_pixel_with_clipping (GdkPixbuf *pixbuf, gint x, gint y, guint rgba)
-{
-	gint    width, height;
-	gint    rowstride, n_channels;
-	guchar *pixels, *pixel;
-
-	width      = gdk_pixbuf_get_width      (pixbuf);
-	height     = gdk_pixbuf_get_height     (pixbuf);
-	rowstride  = gdk_pixbuf_get_rowstride  (pixbuf);
-	n_channels = gdk_pixbuf_get_n_channels (pixbuf);
-	pixels     = gdk_pixbuf_get_pixels     (pixbuf);
-
-	if (x < 0 || x >= width || y < 0 || y >= height)
-		return;
-
-	pixel = pixels + (y * rowstride) + (x * n_channels);
-
-	*pixel       = (rgba >> 24);
-	*(pixel + 1) = (rgba >> 16) & 0x000000ff;
-	*(pixel + 2) = (rgba >>  8) & 0x000000ff;
-
-	if (n_channels > 3)
-	{
-		*(pixel + 3) = rgba & 0x000000ff;
-	}
 }
 
-/* Redraw point in client pixbuf */
+/* Redraw point in client surface */
 
 static void
 update_render_point (EMap *map, EMapPoint *point)
 {
 	EMapPrivate *priv;
-	GdkPixbuf *pb;
+        cairo_t *cr;
 	gdouble px, py;
+        static guchar mask1[] = { 0x00, 0x00, 0xff, 0x00, 0x00,  0x00, 0x00, 0x00,
+                                  0x00, 0xff, 0x00, 0xff, 0x00,  0x00, 0x00, 0x00,
+                                  0xff, 0x00, 0x00, 0x00, 0xff,  0x00, 0x00, 0x00,
+                                  0x00, 0xff, 0x00, 0xff, 0x00,  0x00, 0x00, 0x00,
+                                  0x00, 0x00, 0xff, 0x00, 0x00,  0x00, 0x00, 0x00 };
+        static guchar mask2[] = { 0x00, 0xff, 0x00,  0x00,
+                                  0xff, 0xff, 0xff,  0x00,
+                                  0x00, 0xff, 0x00,  0x00 };
+        cairo_surface_t *mask;
 
 	priv = map->priv;
-	pb = priv->map_render_pixbuf;
-	if (!pb) return;
+
+        if (priv->map_render_surface == NULL)
+                return;
+
+        cr = cairo_create (priv->map_render_surface);
+        cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
 	e_map_world_to_window (map, point->longitude, point->latitude, &px, &py);
-	px += priv->xofs;
-	py += priv->yofs;
-
-	put_pixel_with_clipping (pb, px,     py,     point->rgba);
-	put_pixel_with_clipping (pb, px - 1, py,     point->rgba);
-	put_pixel_with_clipping (pb, px + 1, py,     point->rgba);
-	put_pixel_with_clipping (pb, px,     py - 1, point->rgba);
-	put_pixel_with_clipping (pb, px,     py + 1, point->rgba);
-
-	put_pixel_with_clipping (pb, px - 2, py,     0x000000ff);
-	put_pixel_with_clipping (pb, px + 2, py,     0x000000ff);
-	put_pixel_with_clipping (pb, px,     py - 2, 0x000000ff);
-	put_pixel_with_clipping (pb, px,     py + 2, 0x000000ff);
-	put_pixel_with_clipping (pb, px - 1, py - 1, 0x000000ff);
-	put_pixel_with_clipping (pb, px - 1, py + 1, 0x000000ff);
-	put_pixel_with_clipping (pb, px + 1, py - 1, 0x000000ff);
-	put_pixel_with_clipping (pb, px + 1, py + 1, 0x000000ff);
+	px = floor (px + priv->xofs);
+	py = floor (py + priv->yofs);
+
+        cairo_set_source_rgb (cr, 0, 0, 0);
+        mask = cairo_image_surface_create_for_data (mask1, CAIRO_FORMAT_A8, 5, 5, 8);
+        cairo_mask_surface (cr, mask, px - 2, py - 2);
+        cairo_surface_destroy (mask);
+
+        cairo_set_source_rgba (cr, 
+                               ((point->rgba >> 24) & 0xff) / 255.0,
+                               ((point->rgba >> 16) & 0xff) / 255.0,
+                               ((point->rgba >>  8) & 0xff) / 255.0,
+                               ( point->rgba        & 0xff) / 255.0);
+        mask = cairo_image_surface_create_for_data (mask2, CAIRO_FORMAT_A8, 3, 3, 4);
+        cairo_mask_surface (cr, mask, px - 1, py - 1);
+        cairo_surface_destroy (mask);
+
+        cairo_destroy (cr);
 }
 
 /* Repaint point on X server */
@@ -1377,8 +1361,8 @@ zoom_in_smooth (EMap *map)
 
 	priv = map->priv;
 	window = gtk_widget_get_window (GTK_WIDGET (map));
-	width = gdk_pixbuf_get_width (priv->map_render_pixbuf);
-	height = gdk_pixbuf_get_height (priv->map_render_pixbuf);
+	width = E_MAP_GET_WIDTH (map);
+	height = E_MAP_GET_HEIGHT (map);
 
 	/* Center the target point as much as possible */
 
@@ -1388,7 +1372,7 @@ zoom_in_smooth (EMap *map)
 	/* Render and paint a temporary map without overlays, so they don't get in
 	 * the way (look ugly) while zooming */
 
-	update_render_pixbuf (map, GDK_INTERP_BILINEAR, FALSE);
+	update_render_surface (map, FALSE);
 	gtk_widget_draw (GTK_WIDGET (map), NULL);
 
 	/* Find out where in the area we're going to zoom to */
@@ -1399,7 +1383,7 @@ zoom_in_smooth (EMap *map)
 	 * blowup sequence ends */
 
 	priv->zoom_state = E_MAP_ZOOMED_IN;
-	update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (map, TRUE);
 
 	/* Do the blowup */
 
@@ -1429,7 +1413,7 @@ zoom_in (EMap *map)
 
 	priv->zoom_state = E_MAP_ZOOMED_IN;
 
-	update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (map, TRUE);
 
 	e_map_world_to_window (
 		map, priv->zoom_target_long,
@@ -1462,14 +1446,14 @@ zoom_out (EMap *map)
 	area.width = allocation.width;
 	area.height = allocation.height;
 
-	/* Must be done before update_render_pixbuf() */
+	/* Must be done before update_render_surface() */
 
 	e_map_window_to_world (
 		map, area.width / 2, area.height / 2,
 		&longitude, &latitude);
 
 	priv->zoom_state = E_MAP_ZOOMED_OUT;
-	update_render_pixbuf (map, GDK_INTERP_BILINEAR, TRUE);
+	update_render_surface (map, TRUE);
 
 	e_map_world_to_window (map, longitude, latitude, &x, &y);
 	center_at (map, x + priv->xofs, y + priv->yofs);



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