[libchamplain] Separation of map sources and renderers



commit 5dad0e02a1abfdd419d6183fcf25dadc03e863b4
Author: JiÅ?í Techet <techet gmail com>
Date:   Sat Jun 26 21:36:44 2010 +0200

    Separation of map sources and renderers
    
    Map sources are objects that load data from somewhere (file,
    network, other source) while renderers draw tiles based on
    the data provided by the renderer.
    
    Signed-off-by: JiÅ?í Techet <techet gmail com>

 champlain/Makefile.am                          |   34 +-
 champlain/champlain-enum-types.c.in            |    3 +
 champlain/champlain-error-tile-source.c        |    7 +-
 champlain/champlain-file-cache.c               |   10 +-
 champlain/champlain-file-tile-source.c         |  173 ++++++
 champlain/champlain-file-tile-source.h         |   77 +++
 champlain/champlain-image-renderer.c           |  171 ++++++
 champlain/champlain-image-renderer.h           |   63 ++
 champlain/champlain-local-map-data-source.c    |  193 ------
 champlain/champlain-local-map-data-source.h    |   67 --
 champlain/champlain-map-data-source.c          |  209 -------
 champlain/champlain-map-data-source.h          |   63 --
 champlain/champlain-map-source-factory.c       |   61 ++-
 champlain/champlain-map-source.c               |   86 +++
 champlain/champlain-map-source.h               |    5 +
 champlain/champlain-memphis-renderer.c         |  715 ++++++++++++++++++++++
 champlain/champlain-memphis-renderer.h         |  140 +++++
 champlain/champlain-memphis-tile-source.c      |  782 ------------------------
 champlain/champlain-memphis-tile-source.h      |  107 ----
 champlain/champlain-memphis.h                  |   36 --
 champlain/champlain-network-bbox-tile-source.c |  419 +++++++++++++
 champlain/champlain-network-bbox-tile-source.h |   84 +++
 champlain/champlain-network-map-data-source.c  |  390 ------------
 champlain/champlain-network-map-data-source.h  |   77 ---
 champlain/champlain-network-tile-source.c      |  117 ++--
 champlain/champlain-renderer.c                 |   91 +++
 champlain/champlain-renderer.h                 |   69 +++
 champlain/champlain-tile-cache.c               |   12 +
 champlain/champlain-tile.c                     |   86 ++-
 champlain/champlain-tile.h                     |   14 +
 champlain/champlain-view.c                     |    3 +-
 champlain/champlain.h                          |    5 +
 demos/local-rendering.c                        |  133 ++---
 33 files changed, 2370 insertions(+), 2132 deletions(-)
---
diff --git a/champlain/Makefile.am b/champlain/Makefile.am
index 58df352..c54b601 100644
--- a/champlain/Makefile.am
+++ b/champlain/Makefile.am
@@ -16,12 +16,7 @@ lib_LTLIBRARIES = libchamplain- CHAMPLAIN_API_VERSION@.la
 
 if ENABLE_MEMPHIS
 memphis_headers = \
-        champlain-memphis.h \
-        champlain-memphis-tile-source.h \
-        champlain-map-data-source.h     \
-        champlain-local-map-data-source.h       \
-        champlain-network-map-data-source.h     \
-        champlain-bounding-box.h
+	champlain-memphis-renderer.h
 endif
 
 libchamplain_headers = \
@@ -46,15 +41,16 @@ libchamplain_headers = \
 	champlain-map-source-desc.h	\
 	champlain-polygon.h		\
 	champlain-version.h		\
-	champlain-features.h
+	champlain-features.h	\
+	champlain-renderer.h	\
+	champlain-image-renderer.h	\
+	champlain-file-tile-source.h	\
+	champlain-network-bbox-tile-source.h	\
+	champlain-bounding-box.h
 
 if ENABLE_MEMPHIS
 memphis_sources = \
-        champlain-memphis-tile-source.c		\
-        champlain-map-data-source.c		\
-        champlain-local-map-data-source.c	\
-        champlain-network-map-data-source.c	\
-        champlain-bounding-box.c
+	champlain-memphis-renderer.c
 endif
 
 libchamplain_ CHAMPLAIN_API_VERSION@_la_SOURCES = \
@@ -79,7 +75,12 @@ libchamplain_ CHAMPLAIN_API_VERSION@_la_SOURCES = \
 	champlain-map-source-factory.c	\
 	champlain-map-source-desc.c	\
 	champlain-point.c		\
-	champlain-polygon.c
+	champlain-polygon.c		\
+	champlain-renderer.c	\
+	champlain-image-renderer.c	\
+	champlain-file-tile-source.c	\
+	champlain-network-bbox-tile-source.c	\
+	champlain-bounding-box.c
 
 noinst_HEADERS = \
 	champlain-debug.h  		\
@@ -108,7 +109,12 @@ libchamplain_include_HEADERS = \
 	champlain-marker.h		\
 	champlain-polygon.h		\
 	champlain-version.h		\
-	champlain-features.h
+	champlain-features.h	\
+	champlain-renderer.h	\
+	champlain-image-renderer.h	\
+	champlain-file-tile-source.h	\
+	champlain-network-bbox-tile-source.h	\
+	champlain-bounding-box.h
 
 libchamplain_ CHAMPLAIN_API_VERSION@_la_LIBADD = $(DEPS_LIBS) $(SOUP_LIBS) $(MEMPHIS_LIBS) ../tidy/libtidy-1.0.la
 
diff --git a/champlain/champlain-enum-types.c.in b/champlain/champlain-enum-types.c.in
index d9a3aab..f05069c 100644
--- a/champlain/champlain-enum-types.c.in
+++ b/champlain/champlain-enum-types.c.in
@@ -1,5 +1,8 @@
 /*** BEGIN file-header ***/
 #include "champlain.h"
+#ifdef CHAMPLAIN_HAS_MEMPHIS
+#include "champlain-memphis-renderer.h"
+#endif
 /*** END file-header ***/
 
 /*** BEGIN file-production ***/
diff --git a/champlain/champlain-error-tile-source.c b/champlain/champlain-error-tile-source.c
index 1ecb0f5..044782e 100644
--- a/champlain/champlain-error-tile-source.c
+++ b/champlain/champlain-error-tile-source.c
@@ -110,11 +110,11 @@ fill_tile (ChamplainMapSource *map_source,
   ClutterActor *clone;
   guint size;
 
-  if (champlain_tile_get_content (tile))
+  if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
   {
     /* cache is just validating tile - don't generate error tile in this case - instead use what we have */
-    if (champlain_tile_get_state (tile) != CHAMPLAIN_STATE_DONE)
-      champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+    champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+    champlain_tile_display_content (tile);
     return;
   }
 
@@ -162,4 +162,5 @@ fill_tile (ChamplainMapSource *map_source,
   clutter_texture_set_cogl_texture (CLUTTER_TEXTURE (clone), priv->error_tex);
   champlain_tile_set_content (tile, clone);
   champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+  champlain_tile_display_content (tile);
 }
diff --git a/champlain/champlain-file-cache.c b/champlain/champlain-file-cache.c
index d76f4b5..01dc84b 100644
--- a/champlain/champlain-file-cache.c
+++ b/champlain/champlain-file-cache.c
@@ -630,6 +630,7 @@ tile_loaded_cb (ClutterTexture *texture,
     }
 
   champlain_tile_set_content (tile, actor);
+  champlain_tile_set_state (tile, CHAMPLAIN_STATE_LOADED);
 
   /* Retrieve modification time */
   file = g_file_new_for_path (filename);
@@ -689,16 +690,19 @@ tile_loaded_cb (ClutterTexture *texture,
     {
       /* Tile loaded and no validation needed - done */
       champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+      champlain_tile_display_content (tile);
       goto cleanup;
     }
 
 load_next:
   if (CHAMPLAIN_IS_MAP_SOURCE(next_source))
     champlain_map_source_fill_tile (next_source, tile);
-  else if (champlain_tile_get_content (tile) &&
-           champlain_tile_get_state (tile) != CHAMPLAIN_STATE_DONE)
+  else if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
+  {
     /* if we have some content, use the tile even if it wasn't validated */
     champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+    champlain_tile_display_content (tile);
+  }
 
 cleanup:
   g_free (filename);
@@ -712,7 +716,7 @@ fill_tile (ChamplainMapSource *map_source,
   g_return_if_fail (CHAMPLAIN_IS_FILE_CACHE (map_source));
   g_return_if_fail (CHAMPLAIN_IS_TILE (tile));
 
-  if (!champlain_tile_get_content (tile))
+  if (champlain_tile_get_state (tile) != CHAMPLAIN_STATE_LOADED)
     {
       ChamplainFileCache *file_cache = CHAMPLAIN_FILE_CACHE(map_source);
       TileLoadedCallbackData *callback_data;
diff --git a/champlain/champlain-file-tile-source.c b/champlain/champlain-file-tile-source.c
new file mode 100644
index 0000000..a678f36
--- /dev/null
+++ b/champlain/champlain-file-tile-source.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * SECTION:champlain-local-map-data-source
+ * @short_description: Loads local map data for #ChamplainMemphisTileSource
+ *
+ * This map data source loads local <ulink role="online-location"
+ * url="http://wiki.openstreetmap.org/wiki/.osm";>
+ * OpenStreetMap XML data files</ulink> (*.osm).
+ *
+ */
+
+#include "champlain-file-tile-source.h"
+
+#include "champlain-debug.h"
+#include "champlain-bounding-box.h"
+#include "champlain-enum-types.h"
+#include "champlain-tile.h"
+
+G_DEFINE_TYPE (ChamplainFileTileSource, champlain_file_tile_source, CHAMPLAIN_TYPE_TILE_SOURCE)
+
+
+
+static void fill_tile (ChamplainMapSource *map_source,
+    ChamplainTile *tile);
+
+static void
+champlain_file_tile_source_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (champlain_file_tile_source_parent_class)->dispose (object);
+}
+
+static void
+champlain_file_tile_source_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (champlain_file_tile_source_parent_class)->finalize (object);
+}
+
+static void
+champlain_file_tile_source_class_init (ChamplainFileTileSourceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass);
+
+  object_class->dispose = champlain_file_tile_source_dispose;
+  object_class->finalize = champlain_file_tile_source_finalize;
+
+  map_source_class->fill_tile = fill_tile;
+}
+
+static void
+champlain_file_tile_source_init (ChamplainFileTileSource *self)
+{
+}
+
+/*
+ * champlain_file_tile_source_new:
+ *
+ * Creates a new instance of #ChamplainFileTileSource.
+ *
+ * Returns: a new #ChamplainFileTileSource.
+ *
+ * Since: 0.6
+ */
+ChamplainFileTileSource*
+champlain_file_tile_source_new_full (const gchar *id,
+    const gchar *name,
+    const gchar *license,
+    const gchar *license_uri,
+    guint min_zoom,
+    guint max_zoom,
+    guint tile_size,
+    ChamplainMapProjection projection)
+{
+  ChamplainFileTileSource * source;
+  source = g_object_new (CHAMPLAIN_TYPE_FILE_TILE_SOURCE, "id", id,
+      "name", name, "license", license, "license-uri", license_uri,
+      "min-zoom-level", min_zoom, "max-zoom-level", max_zoom,
+      "tile-size", tile_size, "projection", projection, NULL);
+  return source;
+}
+
+
+/*
+ * champlain_file_tile_source_load_map_data:
+ * @map_data_source: a #ChamplainFileTileSource
+ * @map_path: a path to a map data file
+ *
+ * Loads the OpenStreetMap XML file at the given path.
+ *
+ * Since: 0.6
+ */
+void
+champlain_file_tile_source_load_map_data (ChamplainFileTileSource *self,
+    const gchar *map_path)
+{
+  g_return_if_fail (CHAMPLAIN_IS_FILE_TILE_SOURCE (self));
+
+  ChamplainRenderer *renderer;
+  gchar *data;
+  gsize length;
+
+  if (!g_file_get_contents (map_path, &data, &length, NULL))
+    {
+      g_critical ("Error: \"%s\" cannot be read.", map_path);
+      return;
+    }
+
+  renderer =  champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (self));
+  champlain_renderer_set_data (renderer, data, length);
+  g_free (data);
+}
+
+static void
+tile_rendered_cb (ChamplainTile *tile,
+    ChamplainRenderCallbackData *data,
+    ChamplainMapSource *map_source)
+{
+  ChamplainTileSource *tile_source = CHAMPLAIN_TILE_SOURCE(map_source);
+  ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source);
+  ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+
+  if (!data->error)
+    {
+      if (tile_cache)
+        champlain_tile_cache_store_tile (tile_cache, tile, data->data, data->size);
+
+      champlain_tile_set_fade_in (tile, TRUE);
+      champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+      champlain_tile_display_content (tile);
+    }
+  else if (next_source)
+    champlain_map_source_fill_tile (next_source, tile);
+
+  g_object_unref (map_source);
+  g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+}
+
+static void
+fill_tile (ChamplainMapSource *map_source,
+    ChamplainTile *tile)
+{
+  g_return_if_fail (CHAMPLAIN_IS_FILE_TILE_SOURCE (map_source));
+  g_return_if_fail (CHAMPLAIN_IS_TILE (tile));
+
+  ChamplainRenderer *renderer;
+
+  renderer = champlain_map_source_get_renderer (map_source);
+
+  g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+  g_object_ref (map_source);
+
+  g_signal_connect (tile, "render-complete", G_CALLBACK (tile_rendered_cb), map_source);
+
+  champlain_renderer_render (renderer, tile);
+}
diff --git a/champlain/champlain-file-tile-source.h b/champlain/champlain-file-tile-source.h
new file mode 100644
index 0000000..6276772
--- /dev/null
+++ b/champlain/champlain-file-tile-source.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__CHAMPLAIN_CHAMPLAIN_H_INSIDE__) && !defined (CHAMPLAIN_COMPILATION)
+#error "Only <champlain/champlain.h> can be included directly."
+#endif
+
+#ifndef _CHAMPLAIN_FILE_TILE_SOURCE
+#define _CHAMPLAIN_FILE_TILE_SOURCE
+
+#include <glib-object.h>
+
+#include <champlain/champlain-tile-source.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_FILE_TILE_SOURCE champlain_file_tile_source_get_type()
+
+#define CHAMPLAIN_FILE_TILE_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHAMPLAIN_TYPE_FILE_TILE_SOURCE, ChamplainFileTileSource))
+
+#define CHAMPLAIN_FILE_TILE_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), CHAMPLAIN_TYPE_FILE_TILE_SOURCE, ChamplainFileTileSourceClass))
+
+#define CHAMPLAIN_IS_FILE_TILE_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHAMPLAIN_TYPE_FILE_TILE_SOURCE))
+
+#define CHAMPLAIN_IS_FILE_TILE_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHAMPLAIN_TYPE_FILE_TILE_SOURCE))
+
+#define CHAMPLAIN_FILE_TILE_SOURCE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), CHAMPLAIN_TYPE_FILE_TILE_SOURCE, ChamplainFileTileSourceClass))
+
+typedef struct _ChamplainFileTileSourcePrivate ChamplainFileTileSourcePrivate;
+
+typedef struct {
+  ChamplainTileSource parent;
+} ChamplainFileTileSource;
+
+typedef struct {
+  ChamplainTileSourceClass parent_class;
+} ChamplainFileTileSourceClass;
+
+GType champlain_file_tile_source_get_type (void);
+
+ChamplainFileTileSource*
+champlain_file_tile_source_new_full (const gchar *id,
+    const gchar *name,
+    const gchar *license,
+    const gchar *license_uri,
+    guint min_zoom,
+    guint max_zoom,
+    guint tile_size,
+    ChamplainMapProjection projection);
+
+void champlain_file_tile_source_load_map_data (
+    ChamplainFileTileSource *map_data_source,
+    const gchar *map_path);
+
+G_END_DECLS
+
+#endif /* _CHAMPLAIN_FILE_TILE_SOURCE */
diff --git a/champlain/champlain-image-renderer.c b/champlain/champlain-image-renderer.c
new file mode 100644
index 0000000..599d7a6
--- /dev/null
+++ b/champlain/champlain-image-renderer.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "champlain-image-renderer.h"
+#include <gdk/gdk.h>
+//#include <clutter/clutter.h>
+
+G_DEFINE_TYPE(ChamplainImageRenderer, champlain_image_renderer, CHAMPLAIN_TYPE_RENDERER)
+
+#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHAMPLAIN_TYPE_IMAGE_RENDERER, ChamplainImageRendererPrivate))
+
+struct _ChamplainImageRendererPrivate
+{
+  gchar *data;
+  guint size;
+};
+
+static void set_data (ChamplainRenderer *renderer, const gchar *data, guint size);
+static void render (ChamplainRenderer *renderer, ChamplainTile *tile);
+
+
+static void
+champlain_image_renderer_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (champlain_image_renderer_parent_class)->dispose (object);
+}
+
+
+static void
+champlain_image_renderer_finalize (GObject *object)
+{
+  ChamplainImageRendererPrivate *priv = GET_PRIVATE (object);
+
+  g_free (priv->data);
+
+  G_OBJECT_CLASS (champlain_image_renderer_parent_class)->finalize (object);
+}
+
+
+static void champlain_image_renderer_class_init(ChamplainImageRendererClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+  ChamplainRendererClass *renderer_class = CHAMPLAIN_RENDERER_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ChamplainImageRendererPrivate));
+
+  object_class->finalize = champlain_image_renderer_finalize;
+  object_class->dispose = champlain_image_renderer_dispose;
+
+  renderer_class->set_data = set_data;
+  renderer_class->render = render;
+}
+
+
+static void champlain_image_renderer_init(ChamplainImageRenderer *self)
+{
+  ChamplainImageRendererPrivate *priv = GET_PRIVATE (self);
+
+  self->priv = priv;
+
+  priv->data = NULL;
+}
+
+
+ChamplainImageRenderer *champlain_image_renderer_new(void)
+{
+    return g_object_new (CHAMPLAIN_TYPE_IMAGE_RENDERER, NULL);
+}
+
+
+static void set_data (ChamplainRenderer *renderer, const gchar *data, guint size)
+{
+  ChamplainImageRendererPrivate *priv = GET_PRIVATE (renderer);
+
+  if (priv->data)
+    g_free (priv->data);
+
+  priv->data = g_memdup (data, size);
+  priv->size = size;
+}
+
+
+static void render (ChamplainRenderer *renderer, ChamplainTile *tile)
+{
+  ChamplainImageRendererPrivate *priv = GET_PRIVATE (renderer);
+  ChamplainRenderCallbackData callback_data;
+  GdkPixbufLoader* loader = NULL;
+  GError *error = NULL;
+  ClutterActor *actor = NULL;
+  GdkPixbuf* pixbuf;
+
+  callback_data.error = FALSE;
+
+  loader = gdk_pixbuf_loader_new ();
+  if (!gdk_pixbuf_loader_write (loader,
+                                (const guchar *) priv->data,
+                                priv->size,
+                                &error))
+    {
+      if (error)
+        {
+          g_warning ("Unable to load the pixbuf: %s", error->message);
+          g_error_free (error);
+        }
+
+      goto error;
+    }
+
+  gdk_pixbuf_loader_close (loader, &error);
+  if (error)
+    {
+      g_warning ("Unable to close the pixbuf loader: %s", error->message);
+      g_error_free (error);
+      goto error;
+    }
+
+  /* Load the image into clutter */
+  pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+  actor = clutter_texture_new ();
+  if (!clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (actor),
+           gdk_pixbuf_get_pixels (pixbuf),
+           gdk_pixbuf_get_has_alpha (pixbuf),
+           gdk_pixbuf_get_width (pixbuf),
+           gdk_pixbuf_get_height (pixbuf),
+           gdk_pixbuf_get_rowstride (pixbuf),
+           gdk_pixbuf_get_bits_per_sample (pixbuf) *
+           gdk_pixbuf_get_n_channels (pixbuf) / 8,
+           0, &error))
+    {
+      if (error)
+        {
+          g_warning ("Unable to transfer to clutter: %s", error->message);
+          g_error_free (error);
+        }
+
+      g_object_unref (actor);
+      actor = NULL;
+      goto error;
+    }
+
+  goto finish;
+
+error:
+  callback_data.error = TRUE;
+
+finish:
+  callback_data.data = priv->data;
+  callback_data.size = priv->size;
+
+  champlain_tile_set_content (tile, actor);
+
+  g_signal_emit_by_name (tile, "render-complete", &callback_data);
+
+  if (loader)
+    g_object_unref (loader);
+}
diff --git a/champlain/champlain-image-renderer.h b/champlain/champlain-image-renderer.h
new file mode 100644
index 0000000..add940a
--- /dev/null
+++ b/champlain/champlain-image-renderer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__CHAMPLAIN_CHAMPLAIN_H_INSIDE__) && !defined (CHAMPLAIN_COMPILATION)
+#error "Only <champlain/champlain.h> can be included directly."
+#endif
+
+#ifndef __CHAMPLAIN_IMAGE_RENDERER_H__
+#define __CHAMPLAIN_IMAGE_RENDERER_H__
+
+#include <champlain/champlain-tile.h>
+#include <champlain/champlain-renderer.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_IMAGE_RENDERER            (champlain_image_renderer_get_type())
+#define CHAMPLAIN_IMAGE_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHAMPLAIN_TYPE_IMAGE_RENDERER, ChamplainImageRenderer))
+#define CHAMPLAIN_IMAGE_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHAMPLAIN_TYPE_IMAGE_RENDERER, ChamplainImageRendererClass))
+#define CHAMPLAIN_IS_IMAGE_RENDERER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHAMPLAIN_TYPE_IMAGE_RENDERER))
+#define CHAMPLAIN_IS_IMAGE_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHAMPLAIN_TYPE_IMAGE_RENDERER))
+#define CHAMPLAIN_IMAGE_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHAMPLAIN_TYPE_IMAGE_RENDERER, ChamplainImageRendererClass))
+
+typedef struct _ChamplainImageRendererPrivate ChamplainImageRendererPrivate;
+
+typedef struct _ChamplainImageRenderer ChamplainImageRenderer;
+typedef struct _ChamplainImageRendererClass ChamplainImageRendererClass;
+
+struct _ChamplainImageRenderer
+{
+  ChamplainRenderer parent;
+
+  ChamplainImageRendererPrivate *priv;
+};
+
+struct _ChamplainImageRendererClass
+{
+  ChamplainRendererClass parent_class;
+};
+
+// returns ClutterActor * - the user provides the tile as client data
+
+GType champlain_image_renderer_get_type (void);
+
+ChamplainImageRenderer* champlain_image_renderer_new (void);
+
+G_END_DECLS
+
+#endif /* __CHAMPLAIN_IMAGE_RENDERER_H__ */
diff --git a/champlain/champlain-map-source-factory.c b/champlain/champlain-map-source-factory.c
index 3097652..6c7630f 100644
--- a/champlain/champlain-map-source-factory.c
+++ b/champlain/champlain-map-source-factory.c
@@ -40,7 +40,7 @@
 
 #include "champlain.h"
 #ifdef CHAMPLAIN_HAS_MEMPHIS
-#include "champlain-memphis.h"
+#include "champlain-memphis-renderer.h"
 #endif
 #include "champlain-file-cache.h"
 #include "champlain-defines.h"
@@ -51,6 +51,8 @@
 #include "champlain-network-tile-source.h"
 #include "champlain-map-source-chain.h"
 #include "champlain-error-tile-source.h"
+#include "champlain-image-renderer.h"
+#include "champlain-file-tile-source.h"
 
 #include <glib.h>
 #include <string.h>
@@ -457,7 +459,10 @@ static ChamplainMapSource *
 champlain_map_source_new_generic (
     ChamplainMapSourceDesc *desc, G_GNUC_UNUSED gpointer user_data)
 {
-  return CHAMPLAIN_MAP_SOURCE (champlain_network_tile_source_new_full (
+  ChamplainMapSource *map_source;
+  ChamplainImageRenderer *renderer;
+
+  map_source = CHAMPLAIN_MAP_SOURCE (champlain_network_tile_source_new_full (
       desc->id,
       desc->name,
       desc->license,
@@ -467,6 +472,11 @@ champlain_map_source_new_generic (
       256,
       desc->projection,
       desc->uri_format));
+
+  renderer = champlain_image_renderer_new();
+  champlain_map_source_set_renderer(map_source, CHAMPLAIN_RENDERER(renderer));
+
+  return map_source;
 }
 
 #ifdef CHAMPLAIN_HAS_MEMPHIS
@@ -474,33 +484,38 @@ static ChamplainMapSource *
 champlain_map_source_new_memphis (ChamplainMapSourceDesc *desc,
     G_GNUC_UNUSED gpointer user_data)
 {
-  ChamplainMapDataSource *map_data_source;
+  ChamplainMapSource *map_source;
+  ChamplainMemphisRenderer *renderer;
 
   if (g_strcmp0 (desc->id, CHAMPLAIN_MAP_SOURCE_MEMPHIS_LOCAL) == 0)
     {
-      map_data_source = CHAMPLAIN_MAP_DATA_SOURCE (champlain_local_map_data_source_new ());
-
-      /* Abuse the uri_format field to store an initial data path (optional) */
-      if (desc->uri_format && g_strcmp0 (desc->uri_format, "") != 0)
-        champlain_local_map_data_source_load_map_data (
-            CHAMPLAIN_LOCAL_MAP_DATA_SOURCE (map_data_source),
-            desc->uri_format);
+      map_source = CHAMPLAIN_MAP_SOURCE (champlain_file_tile_source_new_full (
+          desc->id,
+          desc->name,
+          desc->license,
+          desc->license_uri,
+          desc->min_zoom_level,
+          desc->max_zoom_level,
+          256,
+          desc->projection));
     }
-  else if (g_strcmp0 (desc->id, CHAMPLAIN_MAP_SOURCE_MEMPHIS_NETWORK) == 0)
-      map_data_source = CHAMPLAIN_MAP_DATA_SOURCE (champlain_network_map_data_source_new ());
   else
-    return NULL;
+    {
+      map_source = CHAMPLAIN_MAP_SOURCE (champlain_network_bbox_tile_source_new_full (
+          desc->id,
+          desc->name,
+          desc->license,
+          desc->license_uri,
+          desc->min_zoom_level,
+          desc->max_zoom_level,
+          256,
+          desc->projection));
+    }
 
-  return CHAMPLAIN_MAP_SOURCE (champlain_memphis_tile_source_new_full (
-      desc->id,
-      desc->name,
-      desc->license,
-      desc->license_uri,
-      desc->min_zoom_level,
-      desc->max_zoom_level,
-      256,
-      desc->projection,
-      map_data_source));
+  renderer = champlain_memphis_renderer_new_full (256);
+  champlain_map_source_set_renderer(map_source, CHAMPLAIN_RENDERER(renderer));
+
+  return map_source;
 }
 #endif
 
diff --git a/champlain/champlain-map-source.c b/champlain/champlain-map-source.c
index 0c2ffea..66eec48 100644
--- a/champlain/champlain-map-source.c
+++ b/champlain/champlain-map-source.c
@@ -69,6 +69,7 @@ enum
 {
   PROP_0,
   PROP_NEXT_SOURCE,
+  PROP_RENDERER,
 };
 
 static guint champlain_map_source_signals[LAST_SIGNAL] = { 0, };
@@ -76,8 +77,10 @@ static guint champlain_map_source_signals[LAST_SIGNAL] = { 0, };
 struct _ChamplainMapSourcePrivate
 {
   ChamplainMapSource *next_source;
+  ChamplainRenderer *renderer;
 
   gulong sig_handler_id;
+  gulong renderer_sig_handler_id;
 };
 
 static void reload_tiles_cb (ChamplainMapSource *orig, ChamplainMapSource *self);
@@ -98,6 +101,9 @@ champlain_map_source_get_property (GObject *object,
     case PROP_NEXT_SOURCE:
       g_value_set_object (value, priv->next_source);
       break;
+    case PROP_RENDERER:
+      g_value_set_object (value, priv->renderer);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     }
@@ -117,6 +123,10 @@ champlain_map_source_set_property (GObject *object,
       champlain_map_source_set_next_source (map_source,
                                             g_value_get_object (value));
       break;
+    case PROP_RENDERER:
+      champlain_map_source_set_renderer (map_source,
+                                         g_value_get_object (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
     }
@@ -134,6 +144,13 @@ champlain_map_source_dispose (GObject *object)
       priv->next_source = NULL;
     }
 
+  if (priv->renderer)
+    {
+      g_object_unref (priv->renderer);
+
+      priv->renderer = NULL;
+    }
+
   G_OBJECT_CLASS (champlain_map_source_parent_class)->dispose (object);
 }
 
@@ -191,6 +208,20 @@ champlain_map_source_class_init (ChamplainMapSourceClass *klass)
   g_object_class_install_property (object_class, PROP_NEXT_SOURCE, pspec);
 
   /**
+  * ChamplainMapSource:renderer:
+  *
+  * Renderer used to render tiles.
+  *
+  * Since: 0.8
+  */
+  pspec = g_param_spec_object ("renderer",
+                               "Tile renderer",
+                               "Tile renderer used to render tiles",
+                               CHAMPLAIN_TYPE_RENDERER,
+                               G_PARAM_READWRITE);
+  g_object_class_install_property (object_class, PROP_RENDERER, pspec);
+
+  /**
   * ChamplainMapSource::reload-tiles:
   * @map_source: the #ChamplainMapSource that received the signal
   *
@@ -214,7 +245,9 @@ champlain_map_source_init (ChamplainMapSource *map_source)
   map_source->priv = priv;
 
   priv->next_source = NULL;
+  priv->renderer = NULL;
   priv->sig_handler_id = 0;
+  priv->renderer_sig_handler_id = 0;
 }
 
 /**
@@ -235,6 +268,24 @@ champlain_map_source_get_next_source (ChamplainMapSource *map_source)
   return map_source->priv->next_source;
 }
 
+/**
+ * champlain_map_source_get_renderer:
+ * @map_source: a #ChamplainMapSource
+ *
+ * Get the renderer used to render tiles.
+ *
+ * Returns: the renderer.
+ *
+ * Since: 0.8
+ */
+ChamplainRenderer *
+champlain_map_source_get_renderer (ChamplainMapSource *map_source)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MAP_SOURCE (map_source), NULL);
+
+  return map_source->priv->renderer;
+}
+
 static
 void reload_tiles_cb (G_GNUC_UNUSED ChamplainMapSource *orig, ChamplainMapSource *self)
 {
@@ -296,6 +347,41 @@ champlain_map_source_set_next_source (ChamplainMapSource *map_source,
 }
 
 /**
+ * champlain_map_source_set_renderer:
+ * @map_source: a #ChamplainMapSource
+ * @renderer: the renderer used for tile rendering
+ *
+ * Sets the renderer used to render tiles.
+ *
+ * Since: 0.8
+ */
+void
+champlain_map_source_set_renderer (ChamplainMapSource *map_source,
+    ChamplainRenderer *renderer)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MAP_SOURCE (map_source));
+  g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+  ChamplainMapSourcePrivate *priv = map_source->priv;
+
+  if (priv->renderer != NULL)
+    {
+      if (g_signal_handler_is_connected (priv->renderer, priv->renderer_sig_handler_id))
+        g_signal_handler_disconnect (priv->renderer, priv->renderer_sig_handler_id);
+
+      g_object_unref (priv->renderer);
+    }
+
+  g_object_ref_sink (renderer);
+  priv->renderer = renderer;
+
+  priv->renderer_sig_handler_id = g_signal_connect (renderer, "reload-tiles",
+      G_CALLBACK (reload_tiles_cb), map_source);
+
+  g_object_notify (G_OBJECT (map_source), "renderer");
+}
+
+/**
  * champlain_map_source_get_id:
  * @map_source: a #ChamplainMapSource
  *
diff --git a/champlain/champlain-map-source.h b/champlain/champlain-map-source.h
index 4300388..f134d37 100644
--- a/champlain/champlain-map-source.h
+++ b/champlain/champlain-map-source.h
@@ -25,6 +25,7 @@
 
 #include <champlain/champlain-defines.h>
 #include <champlain/champlain-tile.h>
+#include <champlain/champlain-renderer.h>
 
 G_BEGIN_DECLS
 
@@ -84,6 +85,10 @@ ChamplainMapSource *champlain_map_source_get_next_source (ChamplainMapSource *ma
 void champlain_map_source_set_next_source (ChamplainMapSource *map_source,
     ChamplainMapSource *next_source);
 
+ChamplainRenderer *champlain_map_source_get_renderer (ChamplainMapSource *map_source);
+void champlain_map_source_set_renderer (ChamplainMapSource *map_source,
+    ChamplainRenderer *renderer);
+
 const gchar * champlain_map_source_get_id (ChamplainMapSource *map_source);
 const gchar * champlain_map_source_get_name (ChamplainMapSource *map_source);
 const gchar * champlain_map_source_get_license (ChamplainMapSource *map_source);
diff --git a/champlain/champlain-memphis-renderer.c b/champlain/champlain-memphis-renderer.c
new file mode 100644
index 0000000..8a3a33e
--- /dev/null
+++ b/champlain/champlain-memphis-renderer.c
@@ -0,0 +1,715 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * SECTION:champlain-memphis-tile-source
+ * @short_description: A map source that draws tiles locally
+ *
+ * The #ChamplainMemphisRenderer uses the rendering library
+ * <ulink role="online-location" url="https://trac.openstreetmap.ch/trac/memphis/";>
+ * LibMemphis</ulink> to draw <ulink role="online-location" url="http://www.openstreetmap.org/";>
+ * OpenStreetMap</ulink> data. Tiles are rendered in separate threads.
+ * It supports zoom levels 12 to 18.
+ *
+ * The map data is supplied by a #ChamplainMapDataSource.
+ * #ChamplainLocalMapDataSource loads data from a local OSM file.
+ * #ChamplainNetworkMapDataSource uses the OSM API to download data chunks.
+ *
+ * The output of the renderer can be configured with a Memphis rules XML file.
+ * (TODO: link to the specification) The default rules only show
+ * highways as thin black lines.
+ * Once loaded, rules can be queried and edited.
+ */
+
+
+#define DEBUG_FLAG CHAMPLAIN_DEBUG_MEMPHIS
+#include "champlain-debug.h"
+#include "champlain-tile-cache.h"
+#include "champlain-renderer.h"
+#include "champlain-defines.h"
+#include "champlain-enum-types.h"
+#include "champlain-private.h"
+#include "champlain-memphis-renderer.h"
+#include "champlain-bounding-box.h"
+
+#include <gdk/gdk.h>
+
+#include <memphis/memphis.h>
+#include <errno.h>
+#include <string.h>
+
+/* Tuning parameters */
+#define MAX_THREADS 4
+
+const gchar default_rules[] =
+  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+  "<rules version=\"0.1\" background=\"#ffffff\">"
+    "<rule e=\"way\" k=\"highway\" v=\"*\">"
+      "<line color=\"#000000\" width=\"1.0\"/>"
+    "</rule>"
+  "</rules>";
+
+enum
+{
+  PROP_0,
+  PROP_TILE_SIZE,
+  PROP_BOUNDING_BOX
+};
+
+static void render (ChamplainRenderer *renderer, ChamplainTile *tile);
+static void set_data (ChamplainRenderer *renderer, const gchar *data, guint size);
+static void set_bounding_box (ChamplainMemphisRenderer *renderer, ChamplainBoundingBox *bbox);
+
+
+G_DEFINE_TYPE (ChamplainMemphisRenderer, champlain_memphis_renderer, CHAMPLAIN_TYPE_RENDERER)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHAMPLAIN_TYPE_MEMPHIS_RENDERER, ChamplainMemphisRendererPrivate))
+
+struct _ChamplainMemphisRendererPrivate
+{
+  MemphisRuleSet *rules;
+  MemphisRenderer *renderer;
+  GThreadPool *thpool;
+  guint tile_size;
+  ChamplainBoundingBox *bbox;
+};
+
+typedef struct _WorkerThreadData WorkerThreadData;
+
+struct _WorkerThreadData
+{
+  gint x;
+  gint y;
+  guint z;
+  guint size;
+
+  ChamplainRenderer *renderer;
+  ChamplainTile *tile;
+  cairo_surface_t *cst;
+};
+
+/* lock to protect the renderer state while rendering */
+GStaticRWLock MemphisLock = G_STATIC_RW_LOCK_INIT;
+
+
+static void memphis_worker_thread (gpointer data, gpointer user_data);
+void argb_to_rgba (guchar *data,
+    guint size);
+
+static void
+champlain_memphis_renderer_get_property (GObject *object,
+    guint property_id,
+    GValue *value,
+    GParamSpec *pspec)
+{
+  ChamplainMemphisRenderer *renderer = CHAMPLAIN_MEMPHIS_RENDERER (object);
+
+  switch (property_id)
+    {
+      case PROP_TILE_SIZE:
+        g_value_set_uint (value, champlain_memphis_renderer_get_tile_size (renderer));
+        break;
+      case PROP_BOUNDING_BOX:
+        g_value_set_boxed (value, champlain_memphis_renderer_get_bounding_box (renderer));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+champlain_memphis_renderer_set_property (GObject *object,
+    guint property_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  ChamplainMemphisRenderer *renderer = CHAMPLAIN_MEMPHIS_RENDERER (object);
+
+  switch (property_id)
+    {
+      case PROP_TILE_SIZE:
+        champlain_memphis_renderer_set_tile_size (renderer, g_value_get_uint (value));
+        break;
+      case PROP_BOUNDING_BOX:
+        set_bounding_box (renderer, g_value_get_boxed (value));
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+champlain_memphis_renderer_dispose (GObject *object)
+{
+  ChamplainMemphisRenderer *renderer = CHAMPLAIN_MEMPHIS_RENDERER(object);
+  ChamplainMemphisRendererPrivate *priv = renderer->priv;
+
+  if (priv->thpool)
+    {
+      g_thread_pool_free (priv->thpool, FALSE, TRUE);
+      priv->thpool = NULL;
+    }
+  if (priv->renderer)
+    {
+      memphis_renderer_free (priv->renderer);
+      priv->renderer = NULL;
+    }
+  if (priv->rules)
+    {
+      memphis_rule_set_free (priv->rules);
+      priv->rules = NULL;
+    }
+
+  G_OBJECT_CLASS (champlain_memphis_renderer_parent_class)->dispose (object);
+}
+
+static void
+champlain_memphis_renderer_finalize (GObject *object)
+{
+  ChamplainMemphisRenderer *renderer = CHAMPLAIN_MEMPHIS_RENDERER(object);
+  ChamplainMemphisRendererPrivate *priv = renderer->priv;
+
+  champlain_bounding_box_free (priv->bbox);
+
+  G_OBJECT_CLASS (champlain_memphis_renderer_parent_class)->finalize (object);
+}
+
+
+static void
+champlain_memphis_renderer_class_init (ChamplainMemphisRendererClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  ChamplainRendererClass *renderer_class = CHAMPLAIN_RENDERER_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ChamplainMemphisRendererPrivate));
+
+  object_class->get_property = champlain_memphis_renderer_get_property;
+  object_class->set_property = champlain_memphis_renderer_set_property;
+  object_class->dispose = champlain_memphis_renderer_dispose;
+  object_class->finalize = champlain_memphis_renderer_finalize;
+
+  renderer_class->set_data = set_data;
+  renderer_class->render = render;
+
+  g_object_class_install_property (object_class,
+      PROP_TILE_SIZE,
+      g_param_spec_uint ("tile-size",
+          "Tile Size",
+          "The size of the rendered tile",
+          0,
+          G_MAXINT,
+          256,
+          G_PARAM_READWRITE));
+
+  /*
+  * ChamplainMapDataSource:bounding-box:
+  *
+  * The bounding box of the area that contains map data.
+  *
+  * Since: 0.6
+  */
+  g_object_class_install_property (object_class,
+      PROP_BOUNDING_BOX,
+      g_param_spec_boxed ("bounding-box",
+        "Bounding Box",
+        "The bounding box of the renderer",
+        CHAMPLAIN_TYPE_BOUNDING_BOX,
+        G_PARAM_READWRITE));
+
+}
+
+static void
+champlain_memphis_renderer_init (ChamplainMemphisRenderer *renderer)
+{
+  ChamplainMemphisRendererPrivate *priv = GET_PRIVATE(renderer);
+
+  renderer->priv = priv;
+
+  priv->rules = memphis_rule_set_new ();
+  memphis_rule_set_load_from_data (priv->rules, default_rules,
+      strlen (default_rules), NULL);
+
+  priv->renderer = memphis_renderer_new_full (priv->rules, memphis_map_new ());
+
+  priv->thpool = g_thread_pool_new (memphis_worker_thread, renderer,
+      MAX_THREADS, FALSE, NULL);
+
+  priv->bbox = NULL;
+}
+
+ChamplainMemphisRenderer* champlain_memphis_renderer_new_full (guint tile_size)
+{
+  return g_object_new (CHAMPLAIN_TYPE_MEMPHIS_RENDERER, "tile-size", tile_size, NULL);
+}
+
+
+/*
+Transform ARGB (Cairo) to RGBA (GdkPixbuf). RGBA is actualy reversed in
+memory, so the transformation is ARGB -> ABGR (i.e. swapping B and R)
+*/
+void argb_to_rgba (guchar *data,
+    guint size)
+{
+  guint32 *ptr;
+  guint32 *endptr = (guint32 *)data + size / 4;
+  for (ptr = (guint32 *)data; ptr < endptr; ptr++)
+    *ptr = (*ptr & 0xFF00FF00) ^ ((*ptr & 0xFF0000) >> 16) ^ ((*ptr & 0xFF) << 16);
+}
+
+static gboolean
+tile_loaded_cb (gpointer worker_data)
+{
+  WorkerThreadData *data = (WorkerThreadData *) worker_data;
+  ChamplainTile *tile = data->tile;
+  cairo_surface_t *cst = data->cst;
+  ChamplainRenderer *renderer = CHAMPLAIN_RENDERER(data->renderer);
+  ChamplainRenderCallbackData callback_data;
+  cairo_t *cr_clutter;
+  ClutterActor *actor;
+  guint size = data->size;
+  GError *error = NULL;
+  GdkPixbuf * pixbuf = NULL;
+  gchar *buffer = NULL;
+  gsize buffer_size;
+
+  if (tile)
+    g_object_remove_weak_pointer (G_OBJECT (tile), (gpointer*)&data->tile);
+
+  g_free (data);
+
+  if (!tile)
+    {
+      DEBUG ("Tile destroyed while loading");
+      goto error;
+    }
+
+  if (!cst)
+    goto error;
+
+  /* draw the clutter texture */
+  actor = clutter_cairo_texture_new (size, size);
+
+  cr_clutter = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (actor));
+  cairo_set_source_surface (cr_clutter, cst, 0, 0);
+  cairo_paint (cr_clutter);
+  cairo_destroy (cr_clutter);
+
+  /* modify directly the buffer of cairo surface - we don't use it any more
+     and we close the surface anyway */
+  argb_to_rgba (cairo_image_surface_get_data (cst),
+      cairo_image_surface_get_stride (cst) * cairo_image_surface_get_height (cst));
+
+  pixbuf = gdk_pixbuf_new_from_data (cairo_image_surface_get_data (cst),
+               GDK_COLORSPACE_RGB, TRUE, 8, size, size,
+               cairo_image_surface_get_stride (cst), NULL, NULL);
+
+  if (!gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &buffer_size, "png", &error, NULL))
+    goto error;
+
+  champlain_tile_set_content (tile, actor);
+
+  callback_data.error = FALSE;
+  callback_data.data = buffer;
+  callback_data.size = buffer_size;
+  goto finish;
+
+error:
+  callback_data.error = TRUE;
+  callback_data.data = NULL;
+  callback_data.size = 0;
+
+finish:
+  g_signal_emit_by_name (tile, "render-complete", &callback_data);
+
+  if (pixbuf)
+    g_object_unref (pixbuf);
+  if (cst)
+    cairo_surface_destroy (cst);
+  g_object_unref (renderer);
+  g_free (buffer);
+
+  return FALSE;
+}
+
+static void
+memphis_worker_thread (gpointer worker_data,
+    G_GNUC_UNUSED gpointer user_data)
+{
+  WorkerThreadData *data = (WorkerThreadData *)worker_data;
+  ChamplainMemphisRenderer *renderer = CHAMPLAIN_MEMPHIS_RENDERER (data->renderer);
+  gboolean has_data = TRUE;
+
+  data->cst = NULL;
+
+// uncomment when libmemphis works correctly
+//  g_static_rw_lock_reader_lock (&MemphisLock);
+//  has_data = memphis_renderer_tile_has_data (renderer->priv->renderer, data->x, data->y, data->z);
+//  g_static_rw_lock_reader_unlock (&MemphisLock);
+
+  if (has_data)
+    {
+      cairo_t *cr;
+
+      /* create a clutter-independant surface to draw on */
+      data->cst = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, data->size, data->size);
+      cr = cairo_create (data->cst);
+
+      DEBUG ("Draw Tile (%d, %d, %d)", data->x, data->y, data->z);
+
+      g_static_rw_lock_reader_lock (&MemphisLock);
+      memphis_renderer_draw_tile (renderer->priv->renderer, cr, data->x, data->y, data->z);
+      g_static_rw_lock_reader_unlock (&MemphisLock);
+
+      cairo_destroy (cr);
+    }
+
+  clutter_threads_add_idle_full (G_PRIORITY_DEFAULT, tile_loaded_cb, data, NULL);
+}
+
+static void
+render (ChamplainRenderer *renderer,
+  ChamplainTile *tile)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  ChamplainMemphisRendererPrivate *priv = CHAMPLAIN_MEMPHIS_RENDERER (renderer)->priv;
+  GError *error = NULL;
+  WorkerThreadData *data;
+
+  DEBUG ("Render tile (%u, %u, %u)", champlain_tile_get_x (tile),
+         champlain_tile_get_y (tile),
+         champlain_tile_get_zoom_level (tile));
+
+  data = g_new (WorkerThreadData, 1);
+  data->x = champlain_tile_get_x (tile);
+  data->y = champlain_tile_get_y (tile);
+  data->z = champlain_tile_get_zoom_level (tile);
+  data->size = priv->tile_size;
+  data->tile = tile;
+  data->renderer = renderer;
+
+  g_object_add_weak_pointer (G_OBJECT (tile), (gpointer*)&data->tile);
+  g_object_ref (renderer);
+
+  g_thread_pool_push (priv->thpool, data, &error);
+  if (error)
+    {
+      g_error ("Thread pool error: %s", error->message);
+      g_error_free (error);
+      g_free (data);
+      g_object_unref (renderer);
+      g_object_remove_weak_pointer (G_OBJECT (tile), (gpointer*)&data->tile);
+    }
+}
+
+static void
+set_data (ChamplainRenderer *renderer,
+    const gchar *data,
+    guint size)
+{
+  ChamplainMemphisRendererPrivate *priv = GET_PRIVATE (renderer);
+  ChamplainBoundingBox *bbox;
+  GError *err = NULL;
+
+  MemphisMap *map = memphis_map_new ();
+  memphis_map_load_from_data (map, data, size, &err);
+
+  DEBUG ("BBox data received");
+
+  if (err != NULL)
+    {
+      g_critical ("Can't load map data: \"%s\"", err->message);
+      memphis_map_free (map);
+      g_error_free (err);
+      return;
+    }
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  memphis_renderer_set_map (priv->renderer, map);
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  bbox = champlain_bounding_box_new ();
+
+  memphis_map_get_bounding_box (map, &bbox->left, &bbox->top,
+      &bbox->right, &bbox->bottom);
+  g_object_set (G_OBJECT (renderer), "bounding-box", bbox, NULL);
+  champlain_bounding_box_free (bbox);
+
+  g_signal_emit_by_name (CHAMPLAIN_RENDERER (renderer),
+      "reload-tiles", NULL);
+}
+
+/**
+ * champlain_memphis_renderer_load_rules:
+ * @renderer: a #ChamplainMemphisRenderer
+ * @rules_path: a path to a rules file
+ *
+ * Loads a Memphis rules file.
+ *
+ * Since: 0.6
+ */
+void
+champlain_memphis_renderer_load_rules (
+    ChamplainMemphisRenderer *renderer,
+    const gchar *rules_path)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  ChamplainMemphisRendererPrivate *priv = renderer->priv;
+  GError *err = NULL;
+
+  // TODO: Remove test when memphis handles invalid paths properly
+  if (!g_file_test (rules_path, G_FILE_TEST_EXISTS))
+    {
+      g_critical ("Error: \"%s\" does not exist.", rules_path);
+      return;
+    }
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  if (rules_path)
+    {
+      memphis_rule_set_load_from_file (priv->rules, rules_path, &err);
+      if (err != NULL)
+       {
+          g_critical ("Can't load rules file: \"%s\"", err->message);
+          memphis_rule_set_load_from_data (priv->rules, default_rules,
+                                           strlen (default_rules), NULL);
+          g_static_rw_lock_writer_unlock (&MemphisLock);
+          g_error_free (err);
+          return;
+       }
+    }
+  else
+    memphis_rule_set_load_from_data (priv->rules, default_rules,
+                                     strlen (default_rules), NULL);
+
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  g_signal_emit_by_name (CHAMPLAIN_RENDERER (renderer),
+      "reload-tiles", NULL);
+}
+
+
+/*
+ * champlain_memphis_renderer_get_background_color:
+ * @renderer: a #ChamplainMemphisRenderer
+ *
+ * Gets the background color of the map.
+ *
+ * Returns: the background color of the map as a newly-allocated
+ * #ClutterColor.
+ *
+ * Since: 0.6
+ */
+ClutterColor *
+champlain_memphis_renderer_get_background_color (
+    ChamplainMemphisRenderer *renderer)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer), NULL);
+
+  ClutterColor color;
+  guint8 r, b, g, a;
+
+  g_static_rw_lock_reader_lock (&MemphisLock);
+  memphis_rule_set_get_bg_color (renderer->priv->rules, &r, &g, &b, &a);
+  g_static_rw_lock_reader_unlock (&MemphisLock);
+
+  color.red = r;
+  color.green = g;
+  color.blue = b;
+  color.alpha = a;
+  return clutter_color_copy (&color);
+}
+
+/*
+ * champlain_memphis_renderer_set_background_color:
+ * @renderer: a #ChamplainMemphisRenderer
+ * @color: a #ClutterColor
+ *
+ * Sets the background color of the map from a #ClutterColor.
+ *
+ * Since: 0.6
+ */
+void
+champlain_memphis_renderer_set_background_color (
+    ChamplainMemphisRenderer *renderer,
+    const ClutterColor *color)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  memphis_rule_set_set_bg_color (renderer->priv->rules, color->red,
+                                 color->green, color->blue, color->alpha);
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  g_signal_emit_by_name (CHAMPLAIN_RENDERER (renderer),
+      "reload-tiles", NULL);
+}
+
+
+/*
+ * champlain_memphis_renderer_set_rule:
+ * @renderer: a #ChamplainMemphisRenderer
+ * @rule: a #MemphisRule
+ *
+ * Edits or adds a #ChamplainMemphisRule to the rules-set. New rules are appended
+ *  to the list.
+ *
+ * Since: 0.6
+ */
+void
+champlain_memphis_renderer_set_rule (ChamplainMemphisRenderer *renderer,
+    ChamplainMemphisRule *rule)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer) &&
+                    MEMPHIS_RULE (rule));
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  memphis_rule_set_set_rule (renderer->priv->rules, (MemphisRule *)rule);
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  g_signal_emit_by_name (CHAMPLAIN_RENDERER (renderer),
+      "reload-tiles", NULL);
+}
+
+/*
+ * champlain_memphis_renderer_get_rule:
+ * @renderer: a #ChamplainMemphisRenderer
+ * @id: an id string
+ *
+ * Gets the requested #ChamplainMemphisRule.
+ *
+ * Returns: the requested #ChamplainMemphisRule or NULL if none is found.
+ *
+ * Since: 0.6
+ */
+ChamplainMemphisRule *
+champlain_memphis_renderer_get_rule (ChamplainMemphisRenderer *renderer,
+    const gchar *id)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer) &&
+                        id != NULL, NULL);
+
+  MemphisRule *rule;
+
+  g_static_rw_lock_reader_lock (&MemphisLock);
+  rule = memphis_rule_set_get_rule (renderer->priv->rules, id);
+  g_static_rw_lock_reader_unlock (&MemphisLock);
+
+  return (ChamplainMemphisRule *) rule;
+}
+
+/*
+ * champlain_memphis_renderer_get_rule_ids:
+ * @renderer: a #ChamplainMemphisRenderer
+ *
+ * Get a list of rule id's.
+ *
+ * Returns: a #GList of id strings of the form:
+ * key1|key2|...|keyN:value1|value2|...|valueM
+ *
+ * Example: "waterway:river|stream|canal"
+ *
+ * Since: 0.6
+ */
+GList *
+champlain_memphis_renderer_get_rule_ids (ChamplainMemphisRenderer *renderer)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer), NULL);
+
+  GList *list;
+
+  g_static_rw_lock_reader_lock (&MemphisLock);
+  list = memphis_rule_set_get_rule_ids (renderer->priv->rules);
+  g_static_rw_lock_reader_unlock (&MemphisLock);
+
+  return list;
+}
+
+/*
+ * champlain_memphis_renderer_remove_rule:
+ * @renderer: a #ChamplainMemphisRenderer
+ * @id: an id string
+ *
+ * Removes the rule with the given id.
+ *
+ * Since: 0.6
+ */
+void champlain_memphis_renderer_remove_rule (
+    ChamplainMemphisRenderer *renderer,
+    const gchar *id)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  memphis_rule_set_remove_rule (renderer->priv->rules, id);
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  g_signal_emit_by_name (CHAMPLAIN_RENDERER (renderer),
+      "reload-tiles", NULL);
+}
+
+void
+champlain_memphis_renderer_set_tile_size (ChamplainMemphisRenderer *renderer,
+    guint size)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  ChamplainMemphisRendererPrivate *priv = GET_PRIVATE (renderer);
+
+  renderer->priv->tile_size = size;
+
+  g_static_rw_lock_writer_lock (&MemphisLock);
+  memphis_renderer_set_resolution (priv->renderer, size);
+  g_static_rw_lock_writer_unlock (&MemphisLock);
+
+  g_object_notify (G_OBJECT (renderer), "tile-size");
+}
+
+guint
+champlain_memphis_renderer_get_tile_size (ChamplainMemphisRenderer *renderer)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer), 0);
+
+  return renderer->priv->tile_size;
+}
+
+ChamplainBoundingBox *
+champlain_memphis_renderer_get_bounding_box (ChamplainMemphisRenderer *renderer)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer), NULL);
+
+  ChamplainMemphisRendererPrivate *priv = renderer->priv;
+
+  return priv->bbox;
+}
+
+static void
+set_bounding_box (ChamplainMemphisRenderer *renderer, ChamplainBoundingBox *bbox)
+{
+  g_return_if_fail (CHAMPLAIN_IS_MEMPHIS_RENDERER (renderer));
+
+  ChamplainMemphisRendererPrivate *priv = renderer->priv;
+
+  champlain_bounding_box_free (priv->bbox);
+  priv->bbox = champlain_bounding_box_copy (bbox);
+}
+
+
diff --git a/champlain/champlain-memphis-renderer.h b/champlain/champlain-memphis-renderer.h
new file mode 100644
index 0000000..c79a8fa
--- /dev/null
+++ b/champlain/champlain-memphis-renderer.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _CHAMPLAIN_MEMPHIS_RENDERER
+#define _CHAMPLAIN_MEMPHIS_RENDERER
+
+#define __CHAMPLAIN_CHAMPLAIN_H_INSIDE__
+
+#include "champlain/champlain-features.h"
+
+#include <champlain/champlain-tile-source.h>
+#include <champlain/champlain-bounding-box.h>
+// remove me
+//#include <memphis/memphis.h>
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_MEMPHIS_RENDERER champlain_memphis_renderer_get_type()
+
+#define CHAMPLAIN_MEMPHIS_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHAMPLAIN_TYPE_MEMPHIS_RENDERER, ChamplainMemphisRenderer))
+
+#define CHAMPLAIN_MEMPHIS_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), CHAMPLAIN_TYPE_MEMPHIS_RENDERER, ChamplainMemphisRendererClass))
+
+#define CHAMPLAIN_IS_MEMPHIS_RENDERER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHAMPLAIN_TYPE_MEMPHIS_RENDERER))
+
+#define CHAMPLAIN_IS_MEMPHIS_RENDERER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHAMPLAIN_TYPE_MEMPHIS_RENDERER))
+
+#define CHAMPLAIN_MEMPHIS_RENDERER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), CHAMPLAIN_TYPE_MEMPHIS_RENDERER, ChamplainMemphisRendererClass))
+
+typedef struct _ChamplainMemphisRendererPrivate ChamplainMemphisRendererPrivate;
+
+typedef struct {
+  ChamplainRenderer parent;
+
+  ChamplainMemphisRendererPrivate *priv;
+} ChamplainMemphisRenderer;
+
+typedef struct {
+  ChamplainRendererClass parent_class;
+} ChamplainMemphisRendererClass;
+
+
+typedef struct _ChamplainMemphisRule ChamplainMemphisRule;
+typedef struct _ChamplainMemphisRuleAttr ChamplainMemphisRuleAttr;
+
+struct _ChamplainMemphisRuleAttr {
+  guint8 z_min;
+  guint8 z_max;
+  guint8 color_red;
+  guint8 color_green;
+  guint8 color_blue;
+  guint8 color_alpha;
+  gchar *style;
+  gdouble size;
+};
+
+typedef enum {
+  CHAMPLAIN_MEMPHIS_RULE_TYPE_UNKNOWN,
+  CHAMPLAIN_MEMPHIS_RULE_TYPE_NODE,
+  CHAMPLAIN_MEMPHIS_RULE_TYPE_WAY,
+  CHAMPLAIN_MEMPHIS_RULE_TYPE_RELATION
+} ChamplainMemphisRuleType;
+
+struct _ChamplainMemphisRule {
+  gchar **keys;
+  gchar **values;
+  ChamplainMemphisRuleType type;
+  ChamplainMemphisRuleAttr *polygon;
+  ChamplainMemphisRuleAttr *line;
+  ChamplainMemphisRuleAttr *border;
+  ChamplainMemphisRuleAttr *text;
+};
+
+GType champlain_memphis_renderer_get_type (void);
+
+ChamplainMemphisRenderer* champlain_memphis_renderer_new_full (guint tile_size);
+
+void champlain_memphis_renderer_load_rules (
+    ChamplainMemphisRenderer *renderer,
+    const gchar *rules_path);
+
+ClutterColor * champlain_memphis_renderer_get_background_color (
+    ChamplainMemphisRenderer *renderer);
+
+void champlain_memphis_renderer_set_background_color (
+    ChamplainMemphisRenderer *renderer,
+    const ClutterColor *color);
+
+GList * champlain_memphis_renderer_get_rule_ids (
+    ChamplainMemphisRenderer *renderer);
+
+void champlain_memphis_renderer_set_rule (
+    ChamplainMemphisRenderer *renderer,
+    ChamplainMemphisRule *rule);
+
+ChamplainMemphisRule * champlain_memphis_renderer_get_rule (
+    ChamplainMemphisRenderer *renderer,
+    const gchar *id);
+
+void champlain_memphis_renderer_remove_rule (
+    ChamplainMemphisRenderer *renderer,
+    const gchar *id);
+
+ChamplainBoundingBox *champlain_memphis_renderer_get_bounding_box (ChamplainMemphisRenderer *renderer);
+
+void
+champlain_memphis_renderer_set_tile_size (ChamplainMemphisRenderer *self,
+    guint size);
+
+guint
+champlain_memphis_renderer_get_tile_size (ChamplainMemphisRenderer *self);
+
+#undef __CHAMPLAIN_CHAMPLAIN_H_INSIDE__
+
+G_END_DECLS
+
+#endif /* _CHAMPLAIN_MEMPHIS_RENDERER */
diff --git a/champlain/champlain-network-bbox-tile-source.c b/champlain/champlain-network-bbox-tile-source.c
new file mode 100644
index 0000000..7476f5c
--- /dev/null
+++ b/champlain/champlain-network-bbox-tile-source.c
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/*
+ * SECTION:champlain-network-map-data-source
+ * @short_description: Downloads map data for #ChamplainMemphisTileSource
+ *
+ * This map data source downloads the map data from an OpenStreetMap API
+ * server. It supports protocol version 0.5 and 0.6.
+ *
+ * <ulink role="online-location" url="http://wiki.openstreetmap.org/wiki/API";>
+ * http://wiki.openstreetmap.org/wiki/API</ulink>
+ *
+ */
+
+#include "champlain-network-bbox-tile-source.h"
+
+#define DEBUG_FLAG CHAMPLAIN_DEBUG_LOADING
+#include "champlain-debug.h"
+#include "champlain-bounding-box.h"
+#include "champlain-enum-types.h"
+#include "champlain-version.h"
+#include "champlain-tile.h"
+
+#ifdef HAVE_LIBSOUP_GNOME
+#include <libsoup/soup-gnome.h>
+#else
+#include <libsoup/soup.h>
+#endif
+
+G_DEFINE_TYPE (ChamplainNetworkBboxTileSource, champlain_network_bbox_tile_source, CHAMPLAIN_TYPE_TILE_SOURCE)
+
+#define GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE, ChamplainNetworkBboxTileSourcePrivate))
+
+enum
+{
+  /* normal signals */
+  DATA_LOADED,
+  LAST_SIGNAL
+};
+
+enum
+{
+  PROP_0,
+  PROP_API_URI,
+  PROP_PROXY_URI
+};
+
+struct _ChamplainNetworkBboxTileSourcePrivate {
+  gchar *api_uri;
+  gchar *proxy_uri;
+  SoupSession * soup_session;
+};
+
+static guint champlain_network_bbox_tile_source_signals[LAST_SIGNAL] = { 0, };
+
+static void fill_tile (ChamplainMapSource *map_source,
+    ChamplainTile *tile);
+
+
+static void
+champlain_network_bbox_tile_source_get_property (GObject *object,
+    guint property_id,
+    GValue *value,
+    GParamSpec *pspec)
+{
+  ChamplainNetworkBboxTileSource *self =
+      CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (object);
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+
+  switch (property_id)
+    {
+      case PROP_API_URI:
+        g_value_set_string (value,
+            champlain_network_bbox_tile_source_get_api_uri (self));
+        break;
+      case PROP_PROXY_URI:
+        g_value_set_string (value, priv->proxy_uri);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+champlain_network_bbox_tile_source_set_property (GObject *object,
+    guint property_id,
+    const GValue *value,
+    GParamSpec *pspec)
+{
+  ChamplainNetworkBboxTileSource *self =
+      CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (object);
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+
+  switch (property_id)
+    {
+      case PROP_API_URI:
+        champlain_network_bbox_tile_source_set_api_uri (self,
+            g_value_get_string (value));
+        break;
+      case PROP_PROXY_URI:
+        g_free (priv->proxy_uri);
+
+        priv->proxy_uri = g_value_dup_string (value);
+        if (priv->soup_session)
+          g_object_set (G_OBJECT (priv->soup_session), "proxy-uri",
+              soup_uri_new (priv->proxy_uri), NULL);
+        break;
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+champlain_network_bbox_tile_source_dispose (GObject *object)
+{
+  ChamplainNetworkBboxTileSource *self =
+      CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (object);
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+
+  if (priv->soup_session != NULL)
+    {
+      soup_session_abort (priv->soup_session);
+      priv->soup_session = NULL;
+    }
+
+  G_OBJECT_CLASS (champlain_network_bbox_tile_source_parent_class)->dispose (object);
+}
+
+static void
+champlain_network_bbox_tile_source_finalize (GObject *object)
+{
+  ChamplainNetworkBboxTileSource *self =
+      CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (object);
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+
+  g_free (priv->api_uri);
+  g_free (priv->proxy_uri);
+
+  G_OBJECT_CLASS (champlain_network_bbox_tile_source_parent_class)->finalize (object);
+}
+
+static void
+champlain_network_bbox_tile_source_class_init (ChamplainNetworkBboxTileSourceClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (ChamplainNetworkBboxTileSourcePrivate));
+
+  object_class->get_property = champlain_network_bbox_tile_source_get_property;
+  object_class->set_property = champlain_network_bbox_tile_source_set_property;
+  object_class->dispose = champlain_network_bbox_tile_source_dispose;
+  object_class->finalize = champlain_network_bbox_tile_source_finalize;
+
+  ChamplainMapSourceClass *map_source_class = CHAMPLAIN_MAP_SOURCE_CLASS (klass);
+  map_source_class->fill_tile = fill_tile;
+
+  /*
+  * ChamplainNetworkBboxTileSource:api-uri:
+  *
+  * The URI of an OpenStreetMap API server
+  *
+  * Since: 0.6
+  */
+  g_object_class_install_property (object_class,
+      PROP_API_URI,
+      g_param_spec_string ("api_uri",
+        "API URI",
+        "The API URI of an OpenStreetMap server",
+        "http://www.informationfreeway.org/api/0.6";,
+        G_PARAM_READWRITE));
+
+  /*
+  * ChamplainNetworkBboxTileSource:proxy-uri:
+  *
+  * The proxy URI to use to access network
+  *
+  * Since: 0.6
+  */
+  g_object_class_install_property (object_class,
+      PROP_PROXY_URI,
+      g_param_spec_string ("proxy-uri",
+        "Proxy URI",
+        "The proxy URI to use to access network",
+        "",
+        G_PARAM_READWRITE));
+
+  champlain_network_bbox_tile_source_signals[DATA_LOADED] =
+    g_signal_new ("data-loaded", G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+                  0, NULL);
+}
+
+static void
+champlain_network_bbox_tile_source_init (ChamplainNetworkBboxTileSource *self)
+{
+  ChamplainNetworkBboxTileSourcePrivate *priv = GET_PRIVATE (self);
+
+  self->priv = priv;
+
+  priv->api_uri = g_strdup ("http://www.informationfreeway.org/api/0.6";);
+  /* informationfreeway.org is a load-balancer for different api servers */
+  priv->proxy_uri = g_strdup ("");
+  priv->soup_session = soup_session_async_new_with_options (
+      "proxy-uri", soup_uri_new (priv->proxy_uri),
+#ifdef HAVE_LIBSOUP_GNOME
+      SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_GNOME,
+#endif
+      NULL);
+      g_object_set (G_OBJECT (priv->soup_session),
+          "user-agent", "libchamplain/" CHAMPLAIN_VERSION_S,
+          "max-conns-per-host", 2, NULL);
+}
+
+/*
+ * champlain_network_bbox_tile_source_new:
+ *
+ * Creates an instance of #ChamplainNetworkBboxTileSource.
+ *
+ * Returns: a new #ChamplainNetworkBboxTileSource
+ *
+ * Since: 0.6
+ */
+
+ChamplainNetworkBboxTileSource*
+champlain_network_bbox_tile_source_new_full (const gchar *id,
+    const gchar *name,
+    const gchar *license,
+    const gchar *license_uri,
+    guint min_zoom,
+    guint max_zoom,
+    guint tile_size,
+    ChamplainMapProjection projection)
+{
+  ChamplainNetworkBboxTileSource * source;
+  source = g_object_new (CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE, "id", id,
+      "name", name,
+      "license", license,
+      "license-uri", license_uri,
+      "min-zoom-level", min_zoom,
+      "max-zoom-level", max_zoom,
+      "tile-size", tile_size,
+      "projection", projection,
+      NULL);
+  return source;
+}
+
+static void
+load_map_data_cb (G_GNUC_UNUSED SoupSession *session, SoupMessage *msg,
+    gpointer user_data)
+{
+  ChamplainNetworkBboxTileSource *self =
+      CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (user_data);
+  ChamplainRenderer *renderer;
+
+  if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+    {
+      DEBUG ("Unable to download file: %s",
+          soup_status_get_phrase (msg->status_code));
+
+      return;
+    }
+
+  g_signal_emit_by_name (self, "data-loaded", NULL);
+
+  renderer =  champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (self));
+  champlain_renderer_set_data (renderer, msg->response_body->data, msg->response_body->length);
+}
+
+/*
+ * champlain_network_bbox_tile_source_load_map_data:
+ * @map_data_source: a #ChamplainNetworkBboxTileSource
+ * @bound_left: the left bound in degree
+ * @bound_bottom: the lower bound in degree
+ * @bound_right: the right bound in degree
+ * @bound_top: the upper bound in degree
+ *
+ * Asynchronously loads map data within a bounding box from the server.
+ * The box must not exceed an edge size of 0.25 degree. There are also
+ * limitations on the maximum number of nodes that can be requested.
+ *
+ * For details, see: <ulink role="online-location"
+ * url="http://api.openstreetmap.org/api/capabilities";>
+ * http://api.openstreetmap.org/api/capabilities</ulink>
+ *
+ * Since: 0.6
+ */
+void
+champlain_network_bbox_tile_source_load_map_data (
+    ChamplainNetworkBboxTileSource *self,
+    gdouble bound_left,
+    gdouble bound_bottom,
+    gdouble bound_right,
+    gdouble bound_top)
+{
+  g_return_if_fail (CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE (self));
+
+  g_return_if_fail (bound_right - bound_left < 0.25 &&
+      bound_top - bound_bottom < 0.25);
+
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+  SoupMessage *msg;
+  gchar *url;
+
+  url = g_strdup_printf (
+      "http://api.openstreetmap.org/api/0.6/map?bbox=%f,%f,%f,%f";,
+      bound_left, bound_bottom, bound_right, bound_top);
+  msg = soup_message_new ("GET", url);
+
+  DEBUG ("Request BBox data: '%s'", url);
+
+  g_free (url);
+
+  soup_session_queue_message (priv->soup_session, msg, load_map_data_cb, self);
+}
+
+static void
+tile_rendered_cb (ChamplainTile *tile,
+    ChamplainRenderCallbackData *data,
+    ChamplainMapSource *map_source)
+{
+  ChamplainTileSource *tile_source = CHAMPLAIN_TILE_SOURCE(map_source);
+  ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source);
+  ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+
+  if (!data->error)
+    {
+      if (tile_cache)
+        champlain_tile_cache_store_tile (tile_cache, tile, data->data, data->size);
+
+      champlain_tile_set_fade_in (tile, TRUE);
+      champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+      champlain_tile_display_content (tile);
+    }
+  else if (next_source)
+    champlain_map_source_fill_tile (next_source, tile);
+
+  g_object_unref (map_source);
+  g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+}
+
+static void
+fill_tile (ChamplainMapSource *map_source,
+    ChamplainTile *tile)
+{
+  g_return_if_fail (CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE (map_source));
+  g_return_if_fail (CHAMPLAIN_IS_TILE (tile));
+
+  ChamplainRenderer *renderer;
+
+  renderer = champlain_map_source_get_renderer (map_source);
+
+  g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+  g_object_ref (map_source);
+
+  g_signal_connect (tile, "render-complete", G_CALLBACK (tile_rendered_cb), map_source);
+
+  champlain_renderer_render (renderer, tile);
+}
+
+/*
+ * champlain_network_bbox_tile_source_get_api_uri:
+ * @map_data_source: a #ChamplainNetworkBboxTileSource
+ *
+ * Gets the URI of the API server.
+ *
+ * Returns: the URI of the API server.
+ *
+ * Since: 0.6
+ */
+const gchar *
+champlain_network_bbox_tile_source_get_api_uri (
+    ChamplainNetworkBboxTileSource *self)
+{
+  g_return_val_if_fail (CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE (self), NULL);
+
+  return self->priv->api_uri;
+}
+
+/*
+ * champlain_network_bbox_tile_source_set_api_uri:
+ * @map_data_source: a #ChamplainNetworkBboxTileSource
+ * @api_uri: an URI of an API server
+ *
+ * Sets the URI of the API server.
+ *
+ * Since: 0.6
+ */
+void
+champlain_network_bbox_tile_source_set_api_uri (
+    ChamplainNetworkBboxTileSource *self,
+    const gchar *api_uri)
+{
+  g_return_if_fail (CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE (self)
+      && api_uri != NULL);
+
+  ChamplainNetworkBboxTileSourcePrivate *priv = self->priv;
+
+  g_free (priv->api_uri);
+  priv->api_uri = g_strdup (api_uri);
+}
diff --git a/champlain/champlain-network-bbox-tile-source.h b/champlain/champlain-network-bbox-tile-source.h
new file mode 100644
index 0000000..175bb32
--- /dev/null
+++ b/champlain/champlain-network-bbox-tile-source.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009 Simon Wenner <simon wenner ch>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef _CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE
+#define _CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE
+
+#include <glib-object.h>
+
+#include <champlain/champlain-tile-source.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE champlain_network_bbox_tile_source_get_type()
+
+#define CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE, ChamplainNetworkBboxTileSource))
+
+#define CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE, ChamplainNetworkBboxTileSourceClass))
+
+#define CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE))
+
+#define CHAMPLAIN_IS_NETWORK_BBOX_TILE_SOURCE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE))
+
+#define CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), CHAMPLAIN_TYPE_NETWORK_BBOX_TILE_SOURCE, ChamplainNetworkBboxTileSourceClass))
+
+typedef struct _ChamplainNetworkBboxTileSourcePrivate ChamplainNetworkBboxTileSourcePrivate;
+
+typedef struct {
+  ChamplainTileSource parent;
+
+  ChamplainNetworkBboxTileSourcePrivate *priv;
+} ChamplainNetworkBboxTileSource;
+
+typedef struct {
+  ChamplainTileSourceClass parent_class;
+} ChamplainNetworkBboxTileSourceClass;
+
+GType champlain_network_bbox_tile_source_get_type (void);
+
+ChamplainNetworkBboxTileSource* champlain_network_bbox_tile_source_new_full (const gchar *id,
+    const gchar *name,
+    const gchar *license,
+    const gchar *license_uri,
+    guint min_zoom,
+    guint max_zoom,
+    guint tile_size,
+    ChamplainMapProjection projection);
+
+void champlain_network_bbox_tile_source_load_map_data (
+    ChamplainNetworkBboxTileSource *map_data_source,
+    gdouble bound_left,
+    gdouble bound_bottom,
+    gdouble bound_right,
+    gdouble bound_top);
+
+const gchar * champlain_network_bbox_tile_source_get_api_uri (
+    ChamplainNetworkBboxTileSource *map_data_source);
+
+void champlain_network_bbox_tile_source_set_api_uri (
+    ChamplainNetworkBboxTileSource *map_data_source,
+    const gchar *api_uri);
+
+G_END_DECLS
+
+#endif /* _CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE */
diff --git a/champlain/champlain-network-tile-source.c b/champlain/champlain-network-tile-source.c
index 5a7a421..229fa35 100644
--- a/champlain/champlain-network-tile-source.c
+++ b/champlain/champlain-network-tile-source.c
@@ -89,6 +89,12 @@ typedef struct
 typedef struct
 {
   ChamplainMapSource *map_source;
+  gchar *etag;
+} TileRenderedCallbackData;
+
+typedef struct
+{
+  ChamplainMapSource *map_source;
   SoupMessage *msg;
 } TileDestroyedCbData;
 
@@ -512,6 +518,40 @@ destroy_cb_data (TileDestroyedCbData *data,
   g_free (data);
 }
 
+
+static void
+tile_rendered_cb (ChamplainTile *tile, ChamplainRenderCallbackData *data, TileRenderedCallbackData *user_data)
+{
+  ChamplainMapSource *map_source = user_data->map_source;
+  ChamplainTileSource *tile_source = CHAMPLAIN_TILE_SOURCE(map_source);
+  ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source);
+  ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
+  gchar *etag = user_data->etag;
+
+  if (!data->error)
+    {
+      if (etag != NULL)
+        champlain_tile_set_etag (tile, etag);
+
+      if (tile_cache)
+        champlain_tile_cache_store_tile (tile_cache, tile, data->data, data->size);
+
+      champlain_tile_set_fade_in (tile, TRUE);
+      champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+      champlain_tile_display_content (tile);
+    }
+  else
+    {
+      if (next_source)
+        champlain_map_source_fill_tile (next_source, tile);
+    }
+
+  g_object_unref (map_source);
+  g_free (user_data);
+  g_signal_handlers_disconnect_by_func (tile, tile_rendered_cb, data);
+}
+
+
 static void
 tile_loaded_cb (G_GNUC_UNUSED SoupSession *session,
     SoupMessage *msg,
@@ -523,10 +563,10 @@ tile_loaded_cb (G_GNUC_UNUSED SoupSession *session,
   ChamplainTileCache *tile_cache = champlain_tile_source_get_cache (tile_source);
   ChamplainMapSource *next_source = champlain_map_source_get_next_source (map_source);
   ChamplainTile *tile = callback_data->tile;
-  GdkPixbufLoader* loader = NULL;
-  GError *error = NULL;
-  ClutterActor *actor;
   const gchar *etag;
+  TileRenderedCallbackData *data;
+  ChamplainRenderer *renderer;
+
 
   if (tile)
     g_object_remove_weak_pointer (G_OBJECT (tile), (gpointer*)&callback_data->tile);
@@ -564,80 +604,33 @@ tile_loaded_cb (G_GNUC_UNUSED SoupSession *session,
       goto load_next;
     }
 
-  /* Load the data from the http response */
-  loader = gdk_pixbuf_loader_new ();
-  if (!gdk_pixbuf_loader_write (loader,
-                                (const guchar *) msg->response_body->data,
-                                msg->response_body->length,
-                                &error))
-    {
-      if (error)
-        {
-          g_warning ("Unable to load the pixbuf: %s", error->message);
-          g_error_free (error);
-        }
-
-      goto load_next;
-    }
-
-  gdk_pixbuf_loader_close (loader, &error);
-  if (error)
-    {
-      g_warning ("Unable to close the pixbuf loader: %s", error->message);
-      g_error_free (error);
-      goto load_next;
-    }
-
   /* Verify if the server sent an etag and save it */
   etag = soup_message_headers_get (msg->response_headers, "ETag");
   DEBUG ("Received ETag %s", etag);
 
-  if (etag != NULL)
-    champlain_tile_set_etag (tile, etag);
-
-  if (tile_cache)
-    champlain_tile_cache_store_tile (tile_cache, tile, msg->response_body->data, msg->response_body->length);
-
-  /* Load the image into clutter */
-  GdkPixbuf* pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
-  actor = clutter_texture_new ();
-  if (!clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (actor),
-           gdk_pixbuf_get_pixels (pixbuf),
-           gdk_pixbuf_get_has_alpha (pixbuf),
-           gdk_pixbuf_get_width (pixbuf),
-           gdk_pixbuf_get_height (pixbuf),
-           gdk_pixbuf_get_rowstride (pixbuf),
-           gdk_pixbuf_get_bits_per_sample (pixbuf) *
-           gdk_pixbuf_get_n_channels (pixbuf) / 8,
-           0, &error))
-    {
-      if (error)
-        {
-          g_warning ("Unable to transfer to clutter: %s", error->message);
-          g_error_free (error);
-        }
+  data = g_new (TileRenderedCallbackData, 1);
+  data->map_source = map_source;
+  data->etag = g_strdup(etag);
 
-      g_object_unref (actor);
-      goto load_next;
-    }
+  renderer = champlain_map_source_get_renderer (map_source);
 
-  champlain_tile_set_fade_in (tile, TRUE);
-  champlain_tile_set_content (tile, actor);
+  g_signal_connect (tile, "render-complete", G_CALLBACK (tile_rendered_cb), data);
 
-  goto finish;
+  champlain_renderer_set_data (renderer, msg->response_body->data, msg->response_body->length);
+  champlain_renderer_render (renderer, tile);
+
+  return;
 
 load_next:
-  if (loader)
-    g_object_unref (loader);
   if (next_source)
     champlain_map_source_fill_tile (next_source, tile);
   g_object_unref (map_source);
   return;
 
 finish:
-  if (loader)
-    g_object_unref (loader);
+  champlain_tile_set_fade_in (tile, TRUE);
   champlain_tile_set_state (tile, CHAMPLAIN_STATE_DONE);
+  champlain_tile_display_content (tile);
   g_object_unref (map_source);
 }
 
@@ -687,7 +680,7 @@ fill_tile (ChamplainMapSource *map_source,
 
       msg = soup_message_new (SOUP_METHOD_GET, uri);
 
-      if (champlain_tile_get_content (tile))
+      if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
         {
           /* validate tile */
 
diff --git a/champlain/champlain-renderer.c b/champlain/champlain-renderer.c
new file mode 100644
index 0000000..fbee2e9
--- /dev/null
+++ b/champlain/champlain-renderer.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "champlain-renderer.h"
+
+G_DEFINE_TYPE(ChamplainRenderer, champlain_renderer, G_TYPE_OBJECT)
+
+//#define GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE((obj), CHAMPLAIN_TYPE_RENDERER, ChamplainRenderer))
+
+
+//struct _ChamplainRendererPrivate
+//{
+    /* add your private declarations here */
+//};
+
+enum
+{
+  /* normal signals */
+  RELOAD_TILES,
+  LAST_SIGNAL
+};
+
+static guint champlain_renderer_signals[LAST_SIGNAL] = { 0, };
+
+static void
+champlain_renderer_dispose (GObject *object)
+{
+  G_OBJECT_CLASS (champlain_renderer_parent_class)->dispose (object);
+}
+
+static void
+champlain_renderer_finalize (GObject *object)
+{
+  G_OBJECT_CLASS (champlain_renderer_parent_class)->finalize (object);
+}
+
+
+static void champlain_renderer_class_init(ChamplainRendererClass *klass)
+{
+  GObjectClass* object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = champlain_renderer_finalize;
+  object_class->dispose = champlain_renderer_dispose;
+
+  klass->set_data = NULL;
+  klass->render = NULL;
+
+  champlain_renderer_signals[RELOAD_TILES] =
+  g_signal_new ("reload-tiles", G_OBJECT_CLASS_TYPE (object_class),
+                G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+                g_cclosure_marshal_VOID__VOID, G_TYPE_NONE,
+                0, NULL);
+}
+
+
+void champlain_renderer_set_data (ChamplainRenderer *renderer, const gchar *data, guint size)
+{
+  g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+  CHAMPLAIN_RENDERER_GET_CLASS (renderer)->set_data (renderer, data, size);
+}
+
+
+void champlain_renderer_render (ChamplainRenderer *renderer, ChamplainTile *tile)
+{
+  g_return_if_fail (CHAMPLAIN_IS_RENDERER (renderer));
+
+  CHAMPLAIN_RENDERER_GET_CLASS (renderer)->render (renderer, tile);
+}
+
+
+static void champlain_renderer_init(ChamplainRenderer *self)
+{
+}
+
+
diff --git a/champlain/champlain-renderer.h b/champlain/champlain-renderer.h
new file mode 100644
index 0000000..3e460b2
--- /dev/null
+++ b/champlain/champlain-renderer.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Jiri Techet <techet gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#if !defined (__CHAMPLAIN_CHAMPLAIN_H_INSIDE__) && !defined (CHAMPLAIN_COMPILATION)
+#error "Only <champlain/champlain.h> can be included directly."
+#endif
+
+#ifndef __CHAMPLAIN_RENDERER_H__
+#define __CHAMPLAIN_RENDERER_H__
+
+#include <champlain/champlain-tile.h>
+
+G_BEGIN_DECLS
+
+#define CHAMPLAIN_TYPE_RENDERER            (champlain_renderer_get_type())
+#define CHAMPLAIN_RENDERER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), CHAMPLAIN_TYPE_RENDERER, ChamplainRenderer))
+#define CHAMPLAIN_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), CHAMPLAIN_TYPE_RENDERER, ChamplainRendererClass))
+#define CHAMPLAIN_IS_RENDERER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), CHAMPLAIN_TYPE_RENDERER))
+#define CHAMPLAIN_IS_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), CHAMPLAIN_TYPE_RENDERER))
+#define CHAMPLAIN_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), CHAMPLAIN_TYPE_RENDERER, ChamplainRendererClass))
+
+typedef struct _ChamplainRenderer      ChamplainRenderer;
+typedef struct _ChamplainRendererClass    ChamplainRendererClass;
+//typedef struct _ChamplainRendererPrivate    ChamplainRendererPrivate;
+
+struct _ChamplainRenderer
+{
+  GObject parent;
+//  ChamplainRendererPrivate *priv;
+};
+
+struct _ChamplainRendererClass
+{
+  GObjectClass parent_class;
+
+  // takes ownership
+  void (*set_data) (ChamplainRenderer *renderer, const gchar *data, guint size);
+  // only reads coords of the tile
+  void (*render) (ChamplainRenderer *renderer, ChamplainTile *tile);
+};
+
+// returns ClutterActor * - the user provides the tile as client data
+
+GType    champlain_renderer_get_type    (void);
+//GObject*  champlain_renderer_new      (void);
+
+
+void champlain_renderer_set_data (ChamplainRenderer *renderer, const gchar *data, guint size);
+void champlain_renderer_render (ChamplainRenderer *renderer, ChamplainTile *tile);
+
+
+G_END_DECLS
+
+#endif /* __CHAMPLAIN_RENDERER_H__ */
diff --git a/champlain/champlain-tile-cache.c b/champlain/champlain-tile-cache.c
index c3a394c..25576da 100644
--- a/champlain/champlain-tile-cache.c
+++ b/champlain/champlain-tile-cache.c
@@ -50,6 +50,7 @@ static guint get_min_zoom_level (ChamplainMapSource *map_source);
 static guint get_max_zoom_level (ChamplainMapSource *map_source);
 static guint get_tile_size (ChamplainMapSource *map_source);
 static ChamplainMapProjection get_projection (ChamplainMapSource *map_source);
+static void reload_tiles_cb (ChamplainTileCache *tile_cache, G_GNUC_UNUSED gpointer data);
 
 static void
 champlain_tile_cache_get_property (GObject *object,
@@ -161,6 +162,17 @@ champlain_tile_cache_init (ChamplainTileCache *tile_cache)
   tile_cache->priv = priv;
 
   priv->persistent = TRUE;
+  g_signal_connect (tile_cache, "reload-tiles",
+      G_CALLBACK (reload_tiles_cb), NULL);
+}
+
+static
+void reload_tiles_cb (ChamplainTileCache *tile_cache, G_GNUC_UNUSED gpointer data)
+{
+  g_return_if_fail (CHAMPLAIN_IS_TILE_CACHE (tile_cache));
+
+  if (!champlain_tile_cache_get_persistent (tile_cache))
+    champlain_tile_cache_clean (tile_cache);
 }
 
 /**
diff --git a/champlain/champlain-tile.c b/champlain/champlain-tile.c
index 3882466..8e5e29a 100644
--- a/champlain/champlain-tile.c
+++ b/champlain/champlain-tile.c
@@ -52,6 +52,15 @@ enum
   PROP_FADE_IN
 };
 
+enum
+{
+  /* normal signals */
+  RENDER_COMPLETE,
+  LAST_SIGNAL
+};
+
+static guint champlain_tile_signals[LAST_SIGNAL] = { 0, };
+
 struct _ChamplainTilePrivate {
   gint x; /* The x position on the map (in pixels) */
   gint y; /* The y position on the map (in pixels) */
@@ -310,6 +319,12 @@ champlain_tile_class_init (ChamplainTileClass *klass)
           "Tile should fade in",
           FALSE,
           G_PARAM_READWRITE));
+
+  champlain_tile_signals[RENDER_COMPLETE] =
+    g_signal_new ("render-complete", G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST, 0, NULL, NULL,
+                  g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
+                  1, G_TYPE_POINTER);
 }
 
 static void
@@ -536,30 +551,6 @@ champlain_tile_set_state (ChamplainTile *self,
   if (state == priv->state)
     return;
 
-  if (state == CHAMPLAIN_STATE_DONE && priv->content_actor &&
-      clutter_actor_get_parent (priv->content_actor) != CLUTTER_ACTOR (self))
-    {
-      clutter_actor_set_opacity (priv->content_actor, 0);
-      clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->content_actor);
-
-      if (priv->fade_in)
-        {
-          clutter_actor_animate (priv->content_actor,
-              CLUTTER_EASE_IN_CUBIC,
-              500,
-              "opacity", 255,
-              NULL);
-        }
-      else
-        {
-          clutter_actor_animate (priv->content_actor,
-              CLUTTER_LINEAR,
-              150,
-              "opacity", 255,
-              NULL);
-        }
-    }
-
   priv->state = state;
   g_object_notify (G_OBJECT (self), "state");
 }
@@ -693,6 +684,53 @@ champlain_tile_set_content (ChamplainTile *self,
   g_object_notify (G_OBJECT (self), "content");
 }
 
+
+static void
+fade_in_completed (G_GNUC_UNUSED ClutterAnimation *animation, ChamplainTile *self)
+{
+  if (clutter_group_get_n_children (CLUTTER_GROUP (self)) > 1)
+    clutter_actor_destroy (clutter_group_get_nth_child (CLUTTER_GROUP (self), 0));
+}
+
+
+void
+champlain_tile_display_content (ChamplainTile *self)
+{
+  g_return_if_fail (CHAMPLAIN_TILE (self));
+
+  ChamplainTilePrivate *priv = self->priv;
+  ClutterAnimation *animation;
+
+  if (!priv->content_actor)
+    return;
+
+  clutter_actor_set_opacity (priv->content_actor, 0);
+  clutter_container_add_actor (CLUTTER_CONTAINER (self), priv->content_actor);
+
+  if (priv->fade_in)
+    {
+      animation = clutter_actor_animate (priv->content_actor,
+          CLUTTER_EASE_IN_CUBIC,
+          500,
+          "opacity", 255,
+          NULL);
+    }
+  else
+    {
+      animation = clutter_actor_animate (priv->content_actor,
+          CLUTTER_LINEAR,
+          150,
+          "opacity", 255,
+          NULL);
+    }
+
+  g_signal_connect (animation, "completed", G_CALLBACK (fade_in_completed), self);
+
+  g_object_unref (priv->content_actor);
+  priv->content_actor = NULL;
+}
+
+
 /**
  * champlain_tile_get_content:
  * @self: the #ChamplainTile
diff --git a/champlain/champlain-tile.h b/champlain/champlain-tile.h
index 08a14e7..2d53d1b 100644
--- a/champlain/champlain-tile.h
+++ b/champlain/champlain-tile.h
@@ -57,6 +57,7 @@ typedef enum
 {
   CHAMPLAIN_STATE_NONE,
   CHAMPLAIN_STATE_LOADING,
+  CHAMPLAIN_STATE_LOADED,
   CHAMPLAIN_STATE_DONE
 } ChamplainState;
 
@@ -73,6 +74,17 @@ struct _ChamplainTileClass {
   ClutterGroupClass parent_class;
 };
 
+typedef struct _ChamplainRenderCallbackData ChamplainRenderCallbackData;
+
+
+struct _ChamplainRenderCallbackData
+{
+  gboolean error;
+  const gchar *data;
+  guint size;
+};
+
+
 GType champlain_tile_get_type (void);
 
 ChamplainTile* champlain_tile_new (void);
@@ -110,6 +122,8 @@ void champlain_tile_set_modified_time (ChamplainTile *self,
 void champlain_tile_set_fade_in (ChamplainTile *self,
     gboolean fade_in);
 
+void champlain_tile_display_content (ChamplainTile *self);
+
 G_END_DECLS
 
 #endif /* CHAMPLAIN_MAP_TILE_H */
diff --git a/champlain/champlain-view.c b/champlain/champlain-view.c
index 2590e77..ac4470d 100644
--- a/champlain/champlain-view.c
+++ b/champlain/champlain-view.c
@@ -2566,7 +2566,8 @@ tile_destroyed_cb (GObject *gobject,
   ChamplainTile *tile = CHAMPLAIN_TILE (gobject);
   ChamplainViewPrivate *priv = view->priv;
 
-  if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADING)
+  if (champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADING ||
+      champlain_tile_get_state (tile) == CHAMPLAIN_STATE_LOADED)
     {
       priv->tiles_loading--;
       if (priv->tiles_loading == 0)
diff --git a/champlain/champlain.h b/champlain/champlain.h
index bbd57f1..95393a7 100644
--- a/champlain/champlain.h
+++ b/champlain/champlain.h
@@ -42,6 +42,11 @@
 #include "champlain/champlain-error-tile-source.h"
 #include "champlain/champlain-map-source-factory.h"
 #include "champlain/champlain-version.h"
+#include "champlain/champlain-bounding-box.h"
+#include "champlain/champlain-file-tile-source.h"
+#include "champlain/champlain-network-bbox-tile-source.h"
+#include "champlain/champlain-renderer.h"
+#include "champlain/champlain-image-renderer.h"
 
 #undef __CHAMPLAIN_CHAMPLAIN_H_INSIDE__
 
diff --git a/demos/local-rendering.c b/demos/local-rendering.c
index 79fcfd8..7361af6 100644
--- a/demos/local-rendering.c
+++ b/demos/local-rendering.c
@@ -19,7 +19,7 @@
 
 #include <gtk/gtk.h>
 #include <champlain/champlain.h>
-#include <champlain/champlain-memphis.h>
+#include <champlain/champlain-memphis-renderer.h>
 #include <champlain-gtk/champlain-gtk.h>
 #include <clutter-gtk/clutter-gtk.h>
 #include <string.h>
@@ -45,7 +45,7 @@ static GtkWidget *polycolor, *polyminz, *polymaxz;
 static GtkWidget *linecolor, *linesize, *lineminz, *linemaxz;
 static GtkWidget *bordercolor, *bordersize, *borderminz, *bordermaxz;
 static GtkWidget *textcolor, *textsize, *textminz, *textmaxz;
-static MemphisRule *current_rule = NULL;
+static ChamplainMemphisRule *current_rule = NULL;
 
 static ChamplainMapSource *tile_source = NULL;
 
@@ -76,54 +76,29 @@ static void color_clutter_to_gdk (const ClutterColor *clutter_color,
 }
 
 static void
-data_source_state_changed (ChamplainView *view,
-                           GParamSpec *gobject,
+data_source_state_changed (ChamplainNetworkBboxTileSource *source,
                            GtkImage *image)
 {
-  ChamplainState state;
-
-  g_object_get (G_OBJECT (view), "state", &state, NULL);
-  if (state == CHAMPLAIN_STATE_LOADING)
-    {
-      gtk_image_set_from_stock (image, GTK_STOCK_NETWORK, GTK_ICON_SIZE_BUTTON);
-      g_print ("NET DATA SOURCE STATE: loading\n");
-    }
-  else
-    {
-      gtk_image_clear (image);
-      g_print ("NET DATA SOURCE STATE: done\n");
-    }
+  gtk_image_clear (image);
+  g_print ("NET DATA SOURCE STATE: done\n");
+  g_signal_handlers_disconnect_by_func (source,
+                                        data_source_state_changed,
+                                        image);
 }
 
 static void
-load_local_map_data (ChamplainMapSource *source)
+load_network_map_data (ChamplainNetworkBboxTileSource *source, ChamplainView *view)
 {
-  ChamplainLocalMapDataSource *map_data_source;
-
-  map_data_source = CHAMPLAIN_LOCAL_MAP_DATA_SOURCE (
-                      champlain_memphis_tile_source_get_map_data_source (
-                        CHAMPLAIN_MEMPHIS_TILE_SOURCE (source)));
-
-  champlain_local_map_data_source_load_map_data (map_data_source,
-      maps[map_index]);
-}
-
-static void
-load_network_map_data (ChamplainMapSource *source, ChamplainView *view)
-{
-  ChamplainNetworkMapDataSource *map_data_source;
   gdouble lat, lon;
 
-  map_data_source = CHAMPLAIN_NETWORK_MAP_DATA_SOURCE (
-                      champlain_memphis_tile_source_get_map_data_source (
-                        CHAMPLAIN_MEMPHIS_TILE_SOURCE (source)));
-
-  g_signal_connect (map_data_source, "notify::state", G_CALLBACK (data_source_state_changed),
+  g_signal_connect (source, "data-loaded", G_CALLBACK (data_source_state_changed),
                     map_data_state_img);
 
+  gtk_image_set_from_stock (GTK_IMAGE (map_data_state_img), GTK_STOCK_NETWORK, GTK_ICON_SIZE_BUTTON);
+  g_print ("NET DATA SOURCE STATE: loading\n");
   g_object_get (G_OBJECT (view), "latitude", &lat, "longitude", &lon, NULL);
 
-  champlain_network_map_data_source_load_map_data (map_data_source,
+  champlain_network_bbox_tile_source_load_map_data (source,
       lon - 0.008, lat - 0.008, lon + 0.008, lat + 0.008);
 }
 
@@ -135,12 +110,12 @@ load_rules_into_gui (ChamplainView *view)
   GtkTreeIter iter;
   GdkColor gdk_color;
   ClutterColor *clutter_color;
+  ChamplainMemphisRenderer *renderer;
 
-  ids = champlain_memphis_tile_source_get_rule_ids (
-          CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source));
+  renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (tile_source)));
+  ids = champlain_memphis_renderer_get_rule_ids (renderer);
 
-  clutter_color = champlain_memphis_tile_source_get_background_color (
-                    CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source));
+  clutter_color = champlain_memphis_renderer_get_background_color (renderer);
 
   color_clutter_to_gdk (clutter_color, &gdk_color);
   clutter_color_free (clutter_color);
@@ -171,9 +146,9 @@ rule_window_close_cb (GtkWidget *widget, gpointer data)
 }
 
 static void
-rule_apply_cb (GtkWidget *widget, ChamplainMemphisTileSource *source)
+rule_apply_cb (GtkWidget *widget, ChamplainMemphisRenderer *renderer)
 {
-  MemphisRule *rule = current_rule;
+  ChamplainMemphisRule *rule = current_rule;
   GdkColor color;
 
   if (rule->polygon)
@@ -216,11 +191,11 @@ rule_apply_cb (GtkWidget *widget, ChamplainMemphisTileSource *source)
       rule->text->z_max = gtk_spin_button_get_value (GTK_SPIN_BUTTON (textmaxz));
     }
 
-  champlain_memphis_tile_source_set_rule (source, rule);
+  champlain_memphis_renderer_set_rule (renderer, rule);
 }
 
 GtkWidget *
-gtk_memphis_prop_new (gint type, MemphisRuleAttr *attr)
+gtk_memphis_prop_new (gint type, ChamplainMemphisRuleAttr *attr)
 {
   GtkWidget *hbox, *cb, *sb1, *sb2, *sb3;
   GdkColor gcolor;
@@ -278,8 +253,8 @@ gtk_memphis_prop_new (gint type, MemphisRuleAttr *attr)
 }
 
 static void
-create_rule_edit_window (MemphisRule *rule, gchar* id,
-                         ChamplainMemphisTileSource *source)
+create_rule_edit_window (ChamplainMemphisRule *rule, gchar* id,
+                         ChamplainMemphisRenderer *renderer)
 {
   GtkWidget *label, *table, *props, *button;
 
@@ -300,11 +275,11 @@ create_rule_edit_window (MemphisRule *rule, gchar* id,
   gtk_table_set_row_spacings (GTK_TABLE (table), 8);
   label = gtk_label_new (NULL);
 
-  if (rule->type == MEMPHIS_RULE_TYPE_WAY)
+  if (rule->type == CHAMPLAIN_MEMPHIS_RULE_TYPE_WAY)
     gtk_label_set_markup (GTK_LABEL (label), "<b>Way properties</b>");
-  else if (rule->type == MEMPHIS_RULE_TYPE_NODE)
+  else if (rule->type == CHAMPLAIN_MEMPHIS_RULE_TYPE_NODE)
     gtk_label_set_markup (GTK_LABEL (label), "<b>Node properties</b>");
-  else if (rule->type == MEMPHIS_RULE_TYPE_RELATION)
+  else if (rule->type == CHAMPLAIN_MEMPHIS_RULE_TYPE_RELATION)
     gtk_label_set_markup (GTK_LABEL (label), "<b>Relation properties</b>");
   else
     gtk_label_set_markup (GTK_LABEL (label), "<b>Unknown type</b>");
@@ -348,7 +323,7 @@ create_rule_edit_window (MemphisRule *rule, gchar* id,
                     G_CALLBACK (rule_window_close_cb), NULL);
   button = gtk_button_new_from_stock (GTK_STOCK_APPLY);
   g_signal_connect (G_OBJECT (button), "clicked",
-                    G_CALLBACK (rule_apply_cb), source);
+                    G_CALLBACK (rule_apply_cb), renderer);
   gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
 
   GtkWidget *mainbox = gtk_vbox_new (FALSE, 0);
@@ -362,18 +337,19 @@ create_rule_edit_window (MemphisRule *rule, gchar* id,
 static void
 zoom_to_map_data (GtkWidget *widget, ChamplainView *view)
 {
-  ChamplainMapDataSource *data_source;
+  ChamplainMemphisRenderer *renderer;
   ChamplainBoundingBox *bbox;
   gdouble lat, lon;
 
-  data_source = champlain_memphis_tile_source_get_map_data_source (CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source));
-  g_object_get (G_OBJECT (data_source), "bounding-box", &bbox, NULL);
+  renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (tile_source)));
+  g_object_get (G_OBJECT (renderer), "bounding-box", &bbox, NULL);
   champlain_bounding_box_get_center (bbox, &lat, &lon);
 
   champlain_view_center_on (CHAMPLAIN_VIEW(view), lat, lon);
   champlain_view_set_zoom_level (CHAMPLAIN_VIEW(view), 15);
 }
 
+
 static void
 request_osm_data_cb (GtkWidget *widget, ChamplainView *view)
 {
@@ -382,13 +358,8 @@ request_osm_data_cb (GtkWidget *widget, ChamplainView *view)
 
   if (g_strcmp0 (champlain_map_source_get_id (tile_source), "memphis-network") == 0)
     {
-      ChamplainNetworkMapDataSource *data_source =
-        CHAMPLAIN_NETWORK_MAP_DATA_SOURCE (
-          champlain_memphis_tile_source_get_map_data_source (
-            CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source)));
-
-      champlain_network_map_data_source_load_map_data (data_source,
-          lon - 0.008, lat - 0.008, lon + 0.008, lat + 0.008);
+      ChamplainNetworkBboxTileSource *source = CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (tile_source);
+      load_network_map_data (source, view);
     }
 }
 
@@ -401,11 +372,13 @@ bg_color_set_cb (GtkColorButton *widget, ChamplainView *view)
 
   if (strncmp (champlain_map_source_get_id (tile_source), "memphis", 7) == 0)
     {
+      ChamplainMemphisRenderer *renderer;
       ClutterColor clutter_color;
       color_gdk_to_clutter (&gdk_color, &clutter_color);
 
-      champlain_memphis_tile_source_set_background_color (
-        CHAMPLAIN_MEMPHIS_TILE_SOURCE (tile_source), &clutter_color);
+      renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (tile_source)));
+
+      champlain_memphis_renderer_set_background_color (renderer, &clutter_color);
     }
 }
 
@@ -414,9 +387,9 @@ map_source_changed (GtkWidget *widget, ChamplainView *view)
 {
   gchar* id;
   ChamplainMapSource *source;
-  ChamplainLocalMapDataSource *data;
   GtkTreeIter iter;
   GtkTreeModel *model;
+  ChamplainMemphisRenderer *renderer;
 
   if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter))
     return;
@@ -427,6 +400,7 @@ map_source_changed (GtkWidget *widget, ChamplainView *view)
 
   ChamplainMapSourceFactory *factory = champlain_map_source_factory_dup_default ();
   source = champlain_map_source_factory_create (factory, id);
+  renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (source)));
 
   if (source != NULL)
     {
@@ -436,9 +410,8 @@ map_source_changed (GtkWidget *widget, ChamplainView *view)
 
       if (g_strcmp0 (id, "memphis-local") == 0)
         {
-          champlain_memphis_tile_source_load_rules (
-            CHAMPLAIN_MEMPHIS_TILE_SOURCE (source), rules[rules_index]);
-          load_local_map_data (source);
+          champlain_memphis_renderer_load_rules (renderer, rules[rules_index]);
+          champlain_file_tile_source_load_map_data (CHAMPLAIN_FILE_TILE_SOURCE (source), maps[map_index]);
           gtk_widget_hide_all (memphis_box);
           gtk_widget_set_no_show_all (memphis_box, FALSE);
           gtk_widget_set_no_show_all (memphis_local_box, FALSE);
@@ -447,9 +420,8 @@ map_source_changed (GtkWidget *widget, ChamplainView *view)
         }
       else if (g_strcmp0 (id, "memphis-network") == 0)
         {
-          champlain_memphis_tile_source_load_rules (
-            CHAMPLAIN_MEMPHIS_TILE_SOURCE (source), rules[rules_index]);
-          load_network_map_data (source, view);
+          champlain_memphis_renderer_load_rules (renderer, rules[rules_index]);
+          load_network_map_data (CHAMPLAIN_NETWORK_BBOX_TILE_SOURCE (source), view);
           gtk_widget_hide_all (memphis_box);
           gtk_widget_set_no_show_all (memphis_box, FALSE);
           gtk_widget_set_no_show_all (memphis_local_box, TRUE);
@@ -500,7 +472,7 @@ map_data_changed (GtkWidget *widget, ChamplainView *view)
   map_index = index;
 
   if (g_strcmp0 (champlain_map_source_get_id (tile_source), "memphis-local") == 0)
-    load_local_map_data (tile_source);
+    champlain_file_tile_source_load_map_data (CHAMPLAIN_FILE_TILE_SOURCE (tile_source), maps[map_index]);
 }
 
 static void
@@ -518,9 +490,10 @@ rules_changed (GtkWidget *widget, ChamplainView *view)
 
   if (strncmp (champlain_map_source_get_id (tile_source), "memphis", 7) == 0)
     {
-      champlain_memphis_tile_source_load_rules (
-        CHAMPLAIN_MEMPHIS_TILE_SOURCE (tile_source),
-        file);
+      ChamplainMemphisRenderer *renderer;
+
+      renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (tile_source)));
+      champlain_memphis_renderer_load_rules (renderer, file);
       load_rules_into_gui (view);
     }
 }
@@ -656,19 +629,23 @@ void list_item_selected_cb (GtkTreeView *tree_view,
   GtkTreeModel *model;
   char *id;
   GtkTreeSelection *selection = gtk_tree_view_get_selection (tree_view);
-  MemphisRule *rule;
+  ChamplainMemphisRule *rule;
 
   if (rule_edit_window != NULL)
     return;
 
   if (gtk_tree_selection_get_selected (selection, &model, &iter))
     {
+      ChamplainMemphisRenderer *renderer;
+
+      renderer = CHAMPLAIN_MEMPHIS_RENDERER ( champlain_map_source_get_renderer (CHAMPLAIN_MAP_SOURCE (tile_source)));
+
       gtk_tree_model_get (model, &iter, 0, &id, -1);
 
-      rule = champlain_memphis_tile_source_get_rule (CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source), id);
+      rule = champlain_memphis_renderer_get_rule (renderer, id);
 
       if (rule != NULL)
-        create_rule_edit_window (rule, id, CHAMPLAIN_MEMPHIS_TILE_SOURCE(tile_source));
+        create_rule_edit_window (rule, id, renderer);
 
       g_free (id);
     }



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