Index: app/core/gimpprojection.c
===================================================================
--- app/core/gimpprojection.c	(revision 22692)
+++ app/core/gimpprojection.c	(arbetskopia)
@@ -33,6 +33,7 @@
 #include "gimpprojection.h"
 #include "gimpprojection-construct.h"
 
+#include "libgimpmath/gimpmath.h"
 
 enum
 {
@@ -83,6 +84,13 @@ static void       gimp_projection_invali
                                                          gint            h);
 static void       gimp_projection_validate_tile         (TileManager    *tm,
                                                          Tile           *tile);
+static void       write_quarter                         (Tile *dest_tile,
+                                                         Tile *source_tile,
+                                                         gint  bpp,
+                                                         gint  i,
+                                                         gint  j);
+static void       gimp_projection_validate_pyramid_tile (TileManager    *tm,
+                                                         Tile           *tile);
 
 static void       gimp_projection_image_update          (GimpImage      *image,
                                                          gint            x,
@@ -106,7 +114,6 @@ G_DEFINE_TYPE_WITH_CODE (GimpProjection,
 
 static guint projection_signals[LAST_SIGNAL] = { 0 };
 
-
 static void
 gimp_projection_class_init (GimpProjectionClass *klass)
 {
@@ -139,7 +146,9 @@ gimp_projection_init (GimpProjection *pr
 
   proj->type                     = -1;
   proj->bytes                    = 0;
-  proj->tiles                    = NULL;
+
+  proj->pyramid                  = g_new0 (TileManager*, PYRAMID_MAX_LEVELS);
+  proj->top_level                = 0;
 
   proj->update_areas             = NULL;
 
@@ -167,6 +176,7 @@ static void
 gimp_projection_finalize (GObject *object)
 {
   GimpProjection *proj = GIMP_PROJECTION (object);
+  gint level;
 
   if (proj->idle_render.idle_id)
     {
@@ -180,11 +190,13 @@ gimp_projection_finalize (GObject *objec
   gimp_area_list_free (proj->idle_render.update_areas);
   proj->idle_render.update_areas = NULL;
 
-  if (proj->tiles)
-    {
-      tile_manager_unref (proj->tiles);
-      proj->tiles = NULL;
-    }
+  for (level = 0; level <= proj->top_level; level++)
+    if (proj->pyramid[level])
+      {
+        tile_manager_unref (proj->pyramid[level]);
+        proj->pyramid[level] = NULL;
+      }
+  proj->top_level = 0;
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -195,9 +207,11 @@ gimp_projection_get_memsize (GimpObject 
 {
   GimpProjection *projection = GIMP_PROJECTION (object);
   gint64          memsize = 0;
+  gint            level;
 
-  if (projection->tiles)
-    memsize += tile_manager_get_memsize (projection->tiles, FALSE);
+  for (level = 0; level <= projection->top_level; level++)
+    if (projection->pyramid[level])
+      memsize += tile_manager_get_memsize (projection->pyramid[level], FALSE);
 
   return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
                                                                   gui_size);
@@ -223,7 +237,8 @@ gimp_projection_get_pixel_at (GimpPickab
   if (x < 0 || y < 0 || x >= proj->image->width || y >= proj->image->height)
     return FALSE;
 
-  read_pixel_data_1 (gimp_projection_get_tiles (proj), x, y, pixel);
+  read_pixel_data_1 (gimp_projection_get_tiles (proj, PYRAMID_BASE_LEVEL),
+                     x, y, pixel);
 
   return TRUE;
 }
@@ -264,18 +279,36 @@ gimp_projection_new (GimpImage *image)
 }
 
 TileManager *
-gimp_projection_get_tiles (GimpProjection *proj)
+gimp_projection_get_tiles (GimpProjection *proj,
+                           gint level)
 {
   g_return_val_if_fail (GIMP_IS_PROJECTION (proj), NULL);
+  g_return_val_if_fail (level >= PYRAMID_BASE_LEVEL && level <= proj->top_level,
+                        NULL);
+
+  if (proj->pyramid[PYRAMID_BASE_LEVEL] == NULL ||
+
+      tile_manager_width  (proj->pyramid[PYRAMID_BASE_LEVEL]) !=
+      proj->image->width ||
 
-  if (proj->tiles == NULL                                      ||
-      tile_manager_width  (proj->tiles) != proj->image->width ||
-      tile_manager_height (proj->tiles) != proj->image->height)
+      tile_manager_height (proj->pyramid[PYRAMID_BASE_LEVEL]) !=
+      proj->image->height)
     {
       gimp_projection_alloc_tiles (proj);
     }
 
-  return proj->tiles;
+  return proj->pyramid[level];
+}
+
+gint
+gimp_projection_scale_to_level (GimpProjection *proj,
+                                gdouble         scale)
+{
+  g_return_val_if_fail (GIMP_IS_PROJECTION (proj), PYRAMID_BASE_LEVEL);
+
+  return CLAMP ((gint) -(log (scale) / log(2)),
+                PYRAMID_BASE_LEVEL,
+                proj->top_level);
 }
 
 GimpImage *
@@ -354,6 +387,7 @@ gimp_projection_alloc_tiles (GimpProject
 {
   GimpImageType proj_type  = 0;
   gint          proj_bytes = 0;
+  gint          level      = 0;
 
   g_return_if_fail (GIMP_IS_PROJECTION (proj));
 
@@ -378,29 +412,73 @@ gimp_projection_alloc_tiles (GimpProject
       g_assert_not_reached ();
     }
 
-  if (proj->tiles)
+  if (proj->pyramid[PYRAMID_BASE_LEVEL])
     {
-      if (proj_type           != proj->type                       ||
-          proj_bytes          != proj->bytes                      ||
-          proj->image->width  != tile_manager_width (proj->tiles) ||
-          proj->image->height != tile_manager_height (proj->tiles))
+      if (proj_type           != proj->type                               ||
+          proj_bytes          != proj->bytes                              ||
+          proj->image->width  != tile_manager_width  (proj->pyramid[PYRAMID_BASE_LEVEL]) ||
+          proj->image->height != tile_manager_height (proj->pyramid[PYRAMID_BASE_LEVEL]))
         {
-          tile_manager_unref (proj->tiles);
-          proj->tiles = NULL;
+          for (level = 0; level <= proj->top_level; level++)
+            {
+              tile_manager_unref (proj->pyramid[level]);
+              proj->pyramid[level] = NULL;
+            }
+          proj->top_level = 0;
         }
     }
 
-  if (! proj->tiles)
+  if (! proj->pyramid[PYRAMID_BASE_LEVEL])
     {
+
       proj->type  = proj_type;
       proj->bytes = proj_bytes;
 
-      proj->tiles = tile_manager_new (proj->image->width,
-                                      proj->image->height,
-                                      proj->bytes);
-      tile_manager_set_user_data (proj->tiles, proj);
-      tile_manager_set_validate_proc (proj->tiles,
-                                      gimp_projection_validate_tile);
+      for (level = 0; level < PYRAMID_MAX_LEVELS; level++)
+        {
+          gint c            = (1 << level);
+          gint level_width  = proj->image->width  / c;
+          gint level_height = proj->image->height / c;
+
+          if (level_width > TILE_WIDTH / 2 || level_height > TILE_HEIGHT / 2)
+            {
+              proj->pyramid[level] =
+                tile_manager_new (level_width,
+                                  level_height,
+                                  proj->bytes);
+
+              tile_manager_set_level (proj->pyramid[level], level);
+
+              proj->top_level = level;
+
+              g_printerr ("Level %d allocated: %d x %d\n", level, level_width, level_height);
+            }
+          else
+            {
+              /* There is no use having levels that have the same number of
+               * tiles as the parent level.
+               */
+              break;
+            }
+
+          tile_manager_set_user_data (proj->pyramid[level], proj);
+
+          if (level == PYRAMID_BASE_LEVEL)
+            {
+              /* Validate tiles by building from the layers of the image. */
+              tile_manager_set_validate_proc (proj->pyramid[level],
+                                              gimp_projection_validate_tile);
+            }
+          else
+            {
+              /* Use the level below to validate tiles. */
+              tile_manager_set_validate_proc (proj->pyramid[level],
+                                              gimp_projection_validate_pyramid_tile);
+
+              tile_manager_set_level_below (proj->pyramid[level],
+                                            proj->pyramid[level - 1]);
+            }
+        }
     }
 }
 
@@ -631,19 +709,20 @@ gimp_projection_invalidate (GimpProjecti
                             gint            w,
                             gint            h)
 {
-  Tile        *tile;
   TileManager *tm;
-  gint         i, j;
-
-  tm = gimp_projection_get_tiles (proj);
+  gint         level;
 
-  for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
-    for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
-      {
-        tile = tile_manager_get_tile (tm, j, i, FALSE, FALSE);
+  for (level = 0; level <= proj->top_level; level++)
+    {
+      gint c = (1 << level);
 
-        tile_invalidate_tile (&tile, tm, j, i);
-      }
+      tm = gimp_projection_get_tiles (proj, level);
+      tile_manager_invalidate_area (tm,
+                                    x / c,
+                                    y / c,
+                                    w / c,
+                                    h / c);
+    }
 }
 
 static void
@@ -662,6 +741,99 @@ gimp_projection_validate_tile (TileManag
   gimp_projection_construct (proj, x, y, w, h);
 }
 
+static void
+write_quarter (Tile *dest_tile,
+               Tile *source_tile,
+               gint  bpp,
+               gint  i,
+               gint  j)
+{
+  guchar *source_data    = NULL;
+  guchar *dest_data      = NULL;
+
+  gint    source_ewidth  = tile_ewidth  (source_tile);
+  gint    source_eheight = tile_eheight (source_tile);
+  gint    dest_ewidth    = tile_ewidth  (dest_tile);
+  gint    y;
+
+  tile_lock (source_tile);
+  source_data = tile_data_pointer (source_tile, 0, 0);
+
+  dest_data = tile_data_pointer (dest_tile, 0, 0);
+
+  /* Adjust dest pointer to the right quadrant. */
+  dest_data += i * bpp * (TILE_WIDTH / 2) + j * bpp * dest_ewidth * (TILE_HEIGHT / 2);
+
+  for (y = 0; y < source_eheight / 2; y++)
+    {
+      gint    x;
+      guchar *dst = dest_data + y * dest_ewidth * bpp;
+      guchar *src = source_data + y * 2 * source_ewidth * bpp;
+
+      for (x = 0; x < source_ewidth / 2; x++)
+        {
+          int i;
+          for (i = 0; i < bpp; i++)
+            dst[i] = (src[i] +
+                      src[i + bpp] +
+                      src[i + source_ewidth * bpp] +
+                      src[i + source_ewidth * bpp + bpp]) / 4;
+
+
+          dst += bpp;
+          src += bpp * 2;
+        }
+    }
+
+  tile_release (source_tile, FALSE);
+}
+
+static void
+gimp_projection_validate_pyramid_tile (TileManager *tm,
+                                       Tile        *tile)
+{
+  TileManager *level_below    = tile_manager_get_level_below (tm);
+  Tile        *source[2][2]   = { { NULL, NULL },
+                                  { NULL, NULL } };
+  gint         bpp            = tile_bpp (tile);
+  gint         i;
+  gint         j;
+  gint         tile_col;
+  gint         tile_row;
+
+  g_assert(level_below);
+
+  tile_manager_get_tile_col_row (tm, tile, &tile_col, &tile_row);
+
+  g_printerr ("Validating level %d, tile %d, %d\n",
+              tile_manager_get_level (tm), tile_col, tile_row);
+
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      {
+/*         gint a; */
+/*         gint b; */
+
+        source[i][j] = tile_manager_get_at(level_below,
+                                           tile_col * 2 + i,
+                                           tile_row * 2 + j,
+                                           TRUE,
+                                           FALSE);
+/*         tile_manager_get_tile_col_row (level_below, source[i][j], &a, &b); */
+/*         g_printerr ("  Source [%d][%d] level %d, tile %d, %d\n", i, j, */
+/*                     tile_manager_get_level (level_below), a, b); */
+      }
+
+  for (i = 0; i < 2; i++)
+    for (j = 0; j < 2; j++)
+      if (source[i][j])
+        {
+          write_quarter (tile, source[i][j], bpp, i, j);
+
+          /* tile_manager_get_at locks. */
+          tile_release (source[i][j], FALSE);
+        }
+}
 
 /*  image callbacks  */
 
Index: app/core/gimpprojection.h
===================================================================
--- app/core/gimpprojection.h	(revision 22692)
+++ app/core/gimpprojection.h	(arbetskopia)
@@ -45,6 +45,9 @@ struct _GimpProjectionIdleRender
 #define GIMP_IS_PROJECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_PROJECTION))
 #define GIMP_PROJECTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_PROJECTION, GimpProjectionClass))
 
+#define PYRAMID_MAX_LEVELS              10
+#define PYRAMID_BASE_LEVEL              0
+
 
 typedef struct _GimpProjectionClass GimpProjectionClass;
 
@@ -56,7 +59,10 @@ struct _GimpProjection
 
   GimpImageType             type;
   gint                      bytes;
-  TileManager              *tiles;
+
+  /* An image pyramid. Level n + 1 has half the width and height of level n. */
+  TileManager             **pyramid;
+  gint                      top_level;
 
   GSList                   *update_areas;
   GimpProjectionIdleRender  idle_render;
@@ -81,7 +87,13 @@ GType            gimp_projection_get_typ
 
 GimpProjection * gimp_projection_new            (GimpImage            *image);
 
-TileManager    * gimp_projection_get_tiles      (GimpProjection       *proj);
+TileManager    * gimp_projection_get_tiles      (GimpProjection       *proj,
+                                                 gint                  level);
+
+/* Returns which level of the pyramid that should be used for scale 'scale'. */
+gint             gimp_projection_scale_to_level (GimpProjection       *proj,
+                                                 gdouble               scale);
+
 GimpImage      * gimp_projection_get_image      (const GimpProjection *proj);
 GimpImageType    gimp_projection_get_image_type (const GimpProjection *proj);
 gint             gimp_projection_get_bytes      (const GimpProjection *proj);
@@ -91,5 +103,4 @@ void             gimp_projection_flush  
 void             gimp_projection_flush_now      (GimpProjection       *proj);
 void             gimp_projection_finish_draw    (GimpProjection       *proj);
 
-
 #endif /*  __GIMP_PROJECTION_H__  */
Index: app/core/gimpprojection-construct.c
===================================================================
--- app/core/gimpprojection-construct.c	(revision 22692)
+++ app/core/gimpprojection-construct.c	(arbetskopia)
@@ -210,7 +210,8 @@ gimp_projection_construct_layers (GimpPr
       y2 = CLAMP (off_y + gimp_item_height (GIMP_ITEM (layer)), y, y + h);
 
       /* configure the pixel regions  */
-      pixel_region_init (&src1PR, gimp_projection_get_tiles (proj),
+      pixel_region_init (&src1PR,
+                         gimp_projection_get_tiles (proj, PYRAMID_BASE_LEVEL),
                          x1, y1, (x2 - x1), (y2 - y1),
                          TRUE);
 
@@ -306,7 +307,8 @@ gimp_projection_construct_channels (Gimp
 
           /* configure the pixel regions  */
           pixel_region_init (&src1PR,
-                             gimp_projection_get_tiles (proj),
+                             gimp_projection_get_tiles (proj,
+                                                        PYRAMID_BASE_LEVEL),
                              x, y, w, h,
                              TRUE);
           pixel_region_init (&src2PR,
@@ -365,7 +367,8 @@ gimp_projection_initialize (GimpProjecti
       PixelRegion PR;
       guchar      clear[4] = { 0, 0, 0, 0 };
 
-      pixel_region_init (&PR, gimp_projection_get_tiles (proj),
+      pixel_region_init (&PR, gimp_projection_get_tiles (proj,
+                                                         PYRAMID_BASE_LEVEL),
                          x, y, w, h, TRUE);
       color_region (&PR, clear);
     }
Index: app/display/gimpdisplayshell-render.c
===================================================================
--- app/display/gimpdisplayshell-render.c	(revision 22692)
+++ app/display/gimpdisplayshell-render.c	(arbetskopia)
@@ -63,6 +63,10 @@ struct _RenderInfo
   gint              w, h;
   gdouble           scalex;
   gdouble           scaley;
+
+  /* What level in the GimpProjection to use. */
+  gint              level;
+
   gint              src_x;
   gint              src_y;
   gint              dest_bpp;
@@ -750,17 +754,19 @@ render_image_rgb_a (RenderInfo *info)
   gint         y, ye;
   gint         x, xe;
   gint         initial = TRUE;
+  gint         c = (1 << info->level);
 
   y  = info->y;
-  ye = info->y + info->h;
-  xe = info->x + info->w;
+  /* Make sure we don't exceed limits of current pyramid level. */
+  ye = info->y + MIN (tile_manager_height (info->src_tiles), info->h);
+  xe = info->x + MIN (tile_manager_width  (info->src_tiles), info->w);
 
   info->src = render_image_tile_fault (info);
 
   while (TRUE)
     {
       gint error =
-        RINT (floor ((y + 1) / info->scaley) - floor (y / info->scaley));
+        RINT (floor ((y + 1) / (info->scaley * c)) - floor (y / (info->scaley * c)));
 
       if (!initial && (error == 0) && (y & check_mod))
         {
@@ -831,19 +837,26 @@ render_image_init_info_full (RenderInfo 
                              gint              h,
                              GimpProjection   *projection)
 {
+  gint c;
+
   info->shell      = shell;
   info->w          = w;
   info->h          = h;
   info->scalex     = shell->scale_x;
   info->scaley     = shell->scale_y;
+  info->level      = gimp_projection_scale_to_level (projection,
+                                                     shell->scale_x);
   info->dest_bpp   = 3;
   info->dest_bpl   = info->dest_bpp * GIMP_RENDER_BUF_WIDTH;
   info->dest_width = info->dest_bpp * info->w;
 
   render_image_init_info (info, shell, x, y,
-                          gimp_projection_get_tiles (projection));
+                          gimp_projection_get_tiles (projection, info->level));
 
-  info->scale      = render_image_accelerate_scaling (w, info->x, info->scalex);
+  c = (1 << info->level);
+  info->scale      = render_image_accelerate_scaling (w,
+                                                      info->x,
+                                                      info->scalex * c);
 
   if (GIMP_IMAGE_TYPE_HAS_ALPHA (gimp_projection_get_image_type (projection)))
     {
@@ -860,11 +873,13 @@ render_image_init_info (RenderInfo      
                         gint              y,
                         TileManager      *tiles)
 {
+  gint c = (1 << info->level);
+
   info->src_tiles = tiles;
   info->x         = x + shell->offset_x;
   info->y         = y + shell->offset_y;
-  info->src_x     = (gdouble) info->x / info->scalex;
-  info->src_y     = (gdouble) info->y / info->scaley;
+  info->src_x     = (gdouble) info->x / (info->scalex * c);
+  info->src_y     = (gdouble) info->y / (info->scaley * c);
   info->dest      = shell->render_buf;
 }
 
@@ -922,12 +937,22 @@ render_image_tile_fault (RenderInfo *inf
   gint          step;
   gint          bpp;
   gint          x;
+  gint          tile_col;
+  gint          tile_row;
 
   tile = tile_manager_get_tile (info->src_tiles,
                                 info->src_x, info->src_y, TRUE, FALSE);
 
+  if (tile == NULL)
+    {
+      g_printerr ("_fault: tile == NULL, level = %d\n", info->src_tiles);
+    }
+
   g_return_val_if_fail (tile != NULL, tile_buf);
 
+  tile_manager_get_tile_col_row (info->src_tiles, tile, &tile_col, &tile_row);
+
+
   src = tile_data_pointer (tile,
                            info->src_x % TILE_WIDTH,
                            info->src_y % TILE_HEIGHT);
@@ -937,7 +962,7 @@ render_image_tile_fault (RenderInfo *inf
   dest  = tile_buf;
 
   x     = info->src_x;
-  width = info->w;
+  width = MIN (tile_manager_width  (info->src_tiles), info->w);
 
   tilex = info->src_x / TILE_WIDTH;
 
Index: app/base/tile-manager.c
===================================================================
--- app/base/tile-manager.c	(revision 22692)
+++ app/base/tile-manager.c	(arbetskopia)
@@ -57,13 +57,15 @@ tile_manager_new (gint width,
 
   tm = g_slice_new0 (TileManager);
 
-  tm->ref_count  = 1;
-  tm->width      = width;
-  tm->height     = height;
-  tm->bpp        = bpp;
-  tm->ntile_rows = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
-  tm->ntile_cols = (width  + TILE_WIDTH  - 1) / TILE_WIDTH;
-  tm->cached_num = -1;
+  tm->ref_count   = 1;
+  tm->width       = width;
+  tm->height      = height;
+  tm->bpp         = bpp;
+  tm->ntile_rows  = (height + TILE_HEIGHT - 1) / TILE_HEIGHT;
+  tm->ntile_cols  = (width  + TILE_WIDTH  - 1) / TILE_WIDTH;
+  tm->cached_num  = -1;
+  tm->level_below = NULL;
+  tm->level       = 0;
 
   return tm;
 }
@@ -251,6 +253,22 @@ tile_manager_get (TileManager *tm,
   return *tile_ptr;
 }
 
+Tile *
+tile_manager_get_at (TileManager *tm,
+                     gint         tile_col,
+                     gint         tile_row,
+                     gint         wantread,
+                     gint         wantwrite)
+{
+  g_return_val_if_fail (tm != NULL, NULL);
+
+  if (tile_col < 0 || tile_col >= tm->ntile_cols ||
+      tile_row < 0 || tile_row >= tm->ntile_rows)
+    return NULL;
+
+  return tile_manager_get(tm, tile_row * tm->ntile_cols + tile_col, wantread, wantwrite);
+}
+
 void
 tile_manager_validate (TileManager *tm,
                        Tile        *tile)
@@ -323,6 +341,7 @@ tile_invalidate (Tile        **tile_ptr,
   Tile *tile = *tile_ptr;
 
   g_return_if_fail (tile_ptr != NULL);
+  g_return_if_fail (tile != NULL);
   g_return_if_fail (tm != NULL);
 
   if (! tile->valid)
@@ -492,6 +511,28 @@ tile_manager_map (TileManager *tm,
 }
 
 void
+tile_manager_invalidate_area (TileManager *tm,
+                              gint         x,
+                              gint         y,
+                              gint         w,
+                              gint         h)
+{
+  Tile *tile;
+  gint  i;
+  gint  j;
+
+  for (i = y; i < (y + h); i += (TILE_HEIGHT - (i % TILE_HEIGHT)))
+    for (j = x; j < (x + w); j += (TILE_WIDTH - (j % TILE_WIDTH)))
+      {
+        tile = tile_manager_get_tile (tm, j, i, FALSE, FALSE);
+
+        g_assert (tile != NULL);
+
+        tile_invalidate_tile (&tile, tm, j, i);
+      }
+}
+
+void
 tile_manager_set_user_data (TileManager *tm,
                             gpointer     user_data)
 {
@@ -532,6 +573,56 @@ tile_manager_bpp (const TileManager *tm)
   return tm->bpp;
 }
 
+gint
+tile_manager_tiles_per_col (const TileManager *tm)
+{
+  g_return_val_if_fail (tm != NULL, 0);
+
+  return tm->ntile_cols;
+}
+
+gint
+tile_manager_tiles_per_row (const TileManager *tm)
+{
+  g_return_val_if_fail (tm != NULL, 0);
+
+  return tm->ntile_rows;
+}
+
+TileManager *
+tile_manager_get_level_below (const TileManager *tm)
+{
+  g_return_val_if_fail (tm != NULL, NULL);
+
+  return tm->level_below;
+}
+
+void
+tile_manager_set_level_below (TileManager *tm,
+                              TileManager *level_below)
+{
+  g_return_if_fail (tm != NULL);
+
+  tm->level_below = level_below;
+}
+
+void
+tile_manager_set_level (TileManager *tm,
+                        gint         level)
+{
+  g_return_if_fail (tm != NULL);
+
+  tm->level = level;
+}
+
+gint
+tile_manager_get_level (TileManager *tm)
+{
+  g_assert (tm != NULL);
+
+  return tm->level;
+}
+
 void
 tile_manager_get_offsets (const TileManager *tm,
                           gint              *x,
@@ -623,6 +714,23 @@ tile_manager_get_tile_coordinates (TileM
 }
 
 void
+tile_manager_get_tile_col_row (TileManager *tm,
+                               Tile        *tile,
+                               gint        *tile_col,
+                               gint        *tile_row)
+{
+  gint tile_x;
+  gint tile_y;
+
+  g_return_if_fail (tm && tile && tile_col && tile_row);
+
+  tile_manager_get_tile_coordinates (tm, tile, &tile_x, &tile_y);
+
+  *tile_col = tile_x / TILE_WIDTH;
+  *tile_row = tile_y / TILE_HEIGHT;
+}
+
+void
 tile_manager_map_over_tile (TileManager *tm,
                             Tile        *tile,
                             Tile        *srctile)
Index: app/base/tile-manager.h
===================================================================
--- app/base/tile-manager.h	(revision 22692)
+++ app/base/tile-manager.h	(arbetskopia)
@@ -61,6 +61,12 @@ Tile        * tile_manager_get          
                                               gint         wantread,
                                               gint         wantwrite);
 
+Tile        * tile_manager_get_at            (TileManager *tm,
+                                              gint         tile_col,
+                                              gint         tile_row,
+                                              gint         wantread,
+                                              gint         wantwrite);
+
 void          tile_manager_map_tile          (TileManager *tm,
                                               gint         xpixel,
                                               gint         ypixel,
@@ -89,6 +95,12 @@ void          tile_invalidate_tile      
 void          tile_manager_invalidate_tiles  (TileManager       *tm,
                                               Tile              *toplevel_tile);
 
+void          tile_manager_invalidate_area   (TileManager       *tm,
+                                              gint               x,
+                                              gint               y,
+                                              gint               w,
+                                              gint               h);
+
 void          tile_manager_set_user_data     (TileManager       *tm,
                                               gpointer           user_data);
 gpointer      tile_manager_get_user_data     (const TileManager *tm);
@@ -96,6 +108,14 @@ gpointer      tile_manager_get_user_data
 gint          tile_manager_width             (const TileManager *tm);
 gint          tile_manager_height            (const TileManager *tm);
 gint          tile_manager_bpp               (const TileManager *tm);
+gint          tile_manager_tiles_per_col     (const TileManager *tm);
+gint          tile_manager_tiles_per_row     (const TileManager *tm);
+TileManager  *tile_manager_get_level_below   (const TileManager *tm);
+void          tile_manager_set_level_below   (TileManager       *tm,
+                                              TileManager       *level_below);
+void          tile_manager_set_level         (TileManager       *tm,
+                                              gint               level);
+gint          tile_manager_get_level         (TileManager       *tm);
 
 void          tile_manager_get_offsets       (const TileManager *tm,
                                               gint              *x,
@@ -111,6 +131,10 @@ void          tile_manager_get_tile_coor
                                                  Tile        *tile,
                                                  gint        *x,
                                                  gint        *y);
+void          tile_manager_get_tile_col_row     (TileManager *tm,
+                                                 Tile        *tile,
+                                                 gint        *tile_col,
+                                                 gint        *tile_row);
 
 void          tile_manager_map_over_tile        (TileManager *tm,
                                                  Tile        *tile,
Index: app/base/tile-manager-private.h
===================================================================
--- app/base/tile-manager-private.h	(revision 22692)
+++ app/base/tile-manager-private.h	(arbetskopia)
@@ -40,6 +40,14 @@ struct _TileManager
   gint               cached_num;    /*  number of cached tile                */
   Tile              *cached_tile;   /*  the actual cached tile               */
 
+  TileManager       *level_below;   /*  The TileManager containing the level
+                                     *  below in an image pyramid.
+                                     */
+
+  gint               level;         /* The level of this TileManager in an
+                                     * image pyramid.
+                                     */
+
   gpointer           user_data;     /*  hook for hanging data off of         */
 };
 

