[gimp] app: use GimpObjectQueue in lots of places



commit 139a23451ddc588c91610f67daa799afc2f89080
Author: Ell <ell_se yahoo com>
Date:   Sun Mar 25 10:18:46 2018 -0400

    app: use GimpObjectQueue in lots of places
    
    Use GimpObjectQueue, added in the previous commit, in various
    instances where we perform an action on a set of objects.  This
    improves progress reporting, by using a single progress for the
    entire operation, rather than reporting the progress of each object
    individually, and by taking the relative cost of each object into
    account, instead of assuming a uniform cost for all objects.
    
    In particular, this affects the various whole-image operations
    (i.e., transformations and color conversions), operations on linked
    items, and operations on layer groups.  This also affects layers
    with masks, whose progress is now reported together instead of
    individually.
    
    Additionally, this commit fixes erroneous group-layer mask cropping
    during undo when resizing the image, by properly calling
    {start,end}_move() on all the resized layers before starting the
    operation, and when scaling the image, by only scaling top-level
    layers, and letting group layers scale their children themselves.

 app/core/gimpgrouplayer.c              |   30 ++++++
 app/core/gimpimage-color-profile.c     |   41 +++------
 app/core/gimpimage-convert-indexed.c   |   82 ++++++++--------
 app/core/gimpimage-convert-precision.c |  157 +++++++++++++++-----------------
 app/core/gimpimage-convert-type.c      |   37 +++-----
 app/core/gimpimage-flip.c              |   66 ++++----------
 app/core/gimpimage-item-list.c         |   27 +++++-
 app/core/gimpimage-resize.c            |  110 +++++++++-------------
 app/core/gimpimage-rotate.c            |  127 ++++++++++----------------
 app/core/gimpimage-scale.c             |  103 ++++-----------------
 app/core/gimplayer.c                   |  123 ++++++++++++++++++++++---
 11 files changed, 434 insertions(+), 469 deletions(-)
---
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index 8188122..b78ecee 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -38,7 +38,9 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimplayerstack.h"
+#include "gimpobjectqueue.h"
 #include "gimppickable.h"
+#include "gimpprogress.h"
 #include "gimpprojectable.h"
 #include "gimpprojection.h"
 
@@ -780,6 +782,7 @@ gimp_group_layer_scale (GimpLayer             *layer,
   GimpGroupLayer        *group   = GIMP_GROUP_LAYER (layer);
   GimpGroupLayerPrivate *private = GET_PRIVATE (layer);
   GimpItem              *item    = GIMP_ITEM (layer);
+  GimpObjectQueue       *queue   = NULL;
   GList                 *list;
   gdouble                width_factor;
   gdouble                height_factor;
@@ -792,6 +795,14 @@ gimp_group_layer_scale (GimpLayer             *layer,
   old_offset_x = gimp_item_get_offset_x (item);
   old_offset_y = gimp_item_get_offset_y (item);
 
+  if (progress)
+    {
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
+
+      gimp_object_queue_push_container (queue, private->children);
+    }
+
   gimp_group_layer_suspend_resize (group, TRUE);
 
   list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (private->children));
@@ -806,6 +817,9 @@ gimp_group_layer_scale (GimpLayer             *layer,
 
       list = g_list_next (list);
 
+      if (queue)
+        gimp_object_queue_pop (queue);
+
       child_width    = ROUND (width_factor  * gimp_item_get_width  (child));
       child_height   = ROUND (height_factor * gimp_item_get_height (child));
       child_offset_x = ROUND (width_factor  * (gimp_item_get_offset_x (child) -
@@ -836,6 +850,8 @@ gimp_group_layer_scale (GimpLayer             *layer,
     }
 
   gimp_group_layer_resume_resize (group, TRUE);
+
+  g_clear_object (&queue);
 }
 
 static void
@@ -902,8 +918,17 @@ gimp_group_layer_transform (GimpLayer              *layer,
 {
   GimpGroupLayer        *group   = GIMP_GROUP_LAYER (layer);
   GimpGroupLayerPrivate *private = GET_PRIVATE (layer);
+  GimpObjectQueue       *queue   = NULL;
   GList                 *list;
 
+  if (progress)
+    {
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
+
+      gimp_object_queue_push_container (queue, private->children);
+    }
+
   gimp_group_layer_suspend_resize (group, TRUE);
 
   for (list = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (private->children));
@@ -912,6 +937,9 @@ gimp_group_layer_transform (GimpLayer              *layer,
     {
       GimpItem *child = list->data;
 
+      if (queue)
+        gimp_object_queue_pop (queue);
+
       gimp_item_transform (child, context,
                            matrix, direction,
                            interpolation_type,
@@ -919,6 +947,8 @@ gimp_group_layer_transform (GimpLayer              *layer,
     }
 
   gimp_group_layer_resume_resize (group, TRUE);
+
+  g_clear_object (&queue);
 }
 
 static const Babl *
diff --git a/app/core/gimpimage-color-profile.c b/app/core/gimpimage-color-profile.c
index 7115b9e..fafd9ba 100644
--- a/app/core/gimpimage-color-profile.c
+++ b/app/core/gimpimage-color-profile.c
@@ -47,8 +47,8 @@
 #include "gimpimage-private.h"
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
-#include "gimpsubprogress.h"
 
 #include "gimp-intl.h"
 
@@ -676,36 +676,26 @@ gimp_image_convert_profile_layers (GimpImage                *image,
                                    gboolean                  bpc,
                                    GimpProgress             *progress)
 {
-  GList *layers;
-  GList *list;
-  gint   n_drawables  = 0;
-  gint   nth_drawable = 0;
+  GimpObjectQueue *queue;
+  GList           *layers;
+  GList           *list;
+  GimpDrawable    *drawable;
+
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
 
   layers = gimp_image_get_layer_list (image);
 
   for (list = layers; list; list = g_list_next (list))
     {
       if (! gimp_viewable_get_children (list->data))
-        n_drawables++;
+        gimp_object_queue_push (queue, list->data);
     }
 
-  for (list = layers; list; list = g_list_next (list))
-    {
-      GimpDrawable *drawable     = list->data;
-      GimpProgress *sub_progress = NULL;
-
-      if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
-        continue;
-
-      if (progress)
-        {
-          sub_progress = gimp_sub_progress_new (progress);
-          gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                      nth_drawable, n_drawables);
-        }
-
-      nth_drawable++;
+  g_list_free (layers);
 
+  while ((drawable = gimp_object_queue_pop (queue)))
+    {
       gimp_drawable_push_undo (drawable, NULL, NULL,
                                0, 0,
                                gimp_item_get_width  (GIMP_ITEM (drawable)),
@@ -718,15 +708,12 @@ gimp_image_convert_profile_layers (GimpImage                *image,
                                        NULL,
                                        dest_profile,
                                        intent, bpc,
-                                       sub_progress);
+                                       progress);
 
       gimp_drawable_update (drawable, 0, 0, -1, -1);
-
-      if (sub_progress)
-        g_object_unref (sub_progress);
     }
 
-  g_list_free (layers);
+  g_object_unref (queue);
 }
 
 static void
diff --git a/app/core/gimpimage-convert-indexed.c b/app/core/gimpimage-convert-indexed.c
index 85e6397..f6963cf 100644
--- a/app/core/gimpimage-convert-indexed.c
+++ b/app/core/gimpimage-convert-indexed.c
@@ -155,6 +155,7 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimplayer.h"
+#include "gimpobjectqueue.h"
 #include "gimppalette.h"
 #include "gimpprogress.h"
 
@@ -486,8 +487,6 @@ struct _QuantizeObj
   gint          error_freedom;            /* 0=much bleed, 1=controlled bleed */
 
   GimpProgress *progress;
-  gint          nth_layer;
-  gint          n_layers;
 };
 
 typedef struct
@@ -525,9 +524,7 @@ static void          generate_histogram_rgb  (CFHistogram   histogram,
                                               GimpLayer    *layer,
                                               gint          col_limit,
                                               gboolean      dither_alpha,
-                                              GimpProgress *progress,
-                                              gint          nth_layer,
-                                              gint          n_layers);
+                                              GimpProgress *progress);
 
 static QuantizeObj * initialize_median_cut   (GimpImageBaseType      old_type,
                                               gint                   max_colors,
@@ -760,13 +757,13 @@ gimp_image_convert_indexed (GimpImage               *image,
                             GimpProgress            *progress,
                             GError                 **error)
 {
-  QuantizeObj       *quantobj = NULL;
+  QuantizeObj       *quantobj     = NULL;
+  GimpObjectQueue   *queue        = NULL;
+  GimpProgress      *sub_progress = NULL;
   GimpImageBaseType  old_type;
   GList             *all_layers;
   GList             *list;
   GimpColorProfile  *dest_profile = NULL;
-  gint               nth_layer;
-  gint               n_layers;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
   g_return_val_if_fail (gimp_image_get_base_type (image) != GIMP_INDEXED, FALSE);
@@ -795,8 +792,6 @@ gimp_image_convert_indexed (GimpImage               *image,
 
   all_layers = gimp_image_get_layer_list (image);
 
-  n_layers = g_list_length (all_layers);
-
   g_object_freeze_notify (G_OBJECT (image));
 
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT,
@@ -835,10 +830,18 @@ gimp_image_convert_indexed (GimpImage               *image,
       dither_type = GIMP_CONVERT_DITHER_NONE;
     }
 
+  if (progress)
+    {
+      queue        = gimp_object_queue_new (progress);
+      sub_progress = GIMP_PROGRESS (queue);
+
+      gimp_object_queue_push_list (queue, all_layers);
+    }
+
   quantobj = initialize_median_cut (old_type, max_colors, dither_type,
                                     palette_type, custom_palette,
                                     dither_alpha,
-                                    progress);
+                                    sub_progress);
 
   if (palette_type == GIMP_CONVERT_PALETTE_GENERATE)
     {
@@ -855,12 +858,15 @@ gimp_image_convert_indexed (GimpImage               *image,
       num_found_cols = 0;
 
       /*  Build the histogram  */
-      for (list = all_layers, nth_layer = 0;
+      for (list = all_layers;
            list;
-           list = g_list_next (list), nth_layer++)
+           list = g_list_next (list))
         {
           GimpLayer *layer = list->data;
 
+          if (queue)
+            gimp_object_queue_pop (queue);
+
           if (old_type == GIMP_GRAY)
             {
               generate_histogram_gray (quantobj->histogram,
@@ -874,7 +880,7 @@ gimp_image_convert_indexed (GimpImage               *image,
                */
               generate_histogram_rgb (quantobj->histogram,
                                       layer, max_colors, dither_alpha,
-                                      progress, nth_layer, n_layers);
+                                      sub_progress);
             }
         }
     }
@@ -906,7 +912,7 @@ gimp_image_convert_indexed (GimpImage               *image,
                                         palette_type,
                                         custom_palette,
                                         dither_alpha,
-                                        progress);
+                                        sub_progress);
       /* We can skip the first pass (palette creation) */
 
       quantobj->actual_number_of_colors = num_found_cols;
@@ -928,8 +934,13 @@ gimp_image_convert_indexed (GimpImage               *image,
            color_quicksort);
 
   if (progress)
-    gimp_progress_set_text_literal (progress,
-                                    _("Converting to indexed colors (stage 3)"));
+    {
+      gimp_progress_set_text_literal (progress,
+                                      _("Converting to indexed colors (stage 3)"));
+
+      gimp_object_queue_clear (queue);
+      gimp_object_queue_push_list (queue, all_layers);
+    }
 
   /* Initialise data which must persist across indexed layer iterations */
   if (quantobj->second_pass_init)
@@ -955,16 +966,16 @@ gimp_image_convert_indexed (GimpImage               *image,
   }
 
   /*  Convert all layers  */
-  if (quantobj)
-    quantobj->n_layers = n_layers;
-
-  for (list = all_layers, nth_layer = 0;
+  for (list = all_layers;
        list;
-       list = g_list_next (list), nth_layer++)
+       list = g_list_next (list))
     {
       GimpLayer *layer = list->data;
       gboolean   quantize;
 
+      if (queue)
+        gimp_object_queue_pop (queue);
+
       if (gimp_item_is_text_layer (GIMP_ITEM (layer)))
         quantize = dither_text_layers;
       else
@@ -984,7 +995,6 @@ gimp_image_convert_indexed (GimpImage               *image,
                              gimp_image_get_layer_format (image,
                                                           has_alpha));
 
-          quantobj->nth_layer = nth_layer;
           quantobj->second_pass (quantobj, layer, new_buffer);
 
           gimp_drawable_set_buffer (GIMP_DRAWABLE (layer), TRUE, NULL,
@@ -999,7 +1009,7 @@ gimp_image_convert_indexed (GimpImage               *image,
                                       gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)),
                                       dest_profile,
                                       GEGL_DITHER_NONE, GEGL_DITHER_NONE,
-                                      TRUE, NULL);
+                                      TRUE, sub_progress);
         }
     }
 
@@ -1062,6 +1072,8 @@ gimp_image_convert_indexed (GimpImage               *image,
   gimp_image_mode_changed (image);
   g_object_thaw_notify (G_OBJECT (image));
 
+  g_clear_object (&queue);
+
   g_list_free (all_layers);
 
   gimp_unset_busy (image->gimp);
@@ -1146,9 +1158,7 @@ generate_histogram_rgb (CFHistogram   histogram,
                         GimpLayer    *layer,
                         gint          col_limit,
                         gboolean      dither_alpha,
-                        GimpProgress *progress,
-                        gint          nth_layer,
-                        gint          n_layers)
+                        GimpProgress *progress)
 {
   GeglBufferIterator *iter;
   const Babl         *format;
@@ -1340,8 +1350,7 @@ generate_histogram_rgb (CFHistogram   histogram,
 
       if (progress && (count % 16 == 0))
         gimp_progress_set_value (progress,
-                                 (nth_layer + ((gdouble) total_size)/
-                                  layer_size) / (gdouble) n_layers);
+                                 (gdouble) total_size / (gdouble) layer_size);
     }
 
 /*  g_print ("O: col_limit = %d, nfc = %d\n", col_limit, num_found_cols);*/
@@ -3098,8 +3107,6 @@ median_cut_pass2_no_dither_rgb (QuantizeObj *quantobj,
   glong               total_size       = 0;
   glong               layer_size;
   gint                count            = 0;
-  gint                nth_layer        = quantobj->nth_layer;
-  gint                n_layers         = quantobj->n_layers;
 
   gimp_item_get_offset (GIMP_ITEM (layer), &offsetx, &offsety);
 
@@ -3198,8 +3205,7 @@ median_cut_pass2_no_dither_rgb (QuantizeObj *quantobj,
 
       if (quantobj->progress && (count % 16 == 0))
          gimp_progress_set_value (quantobj->progress,
-                                  (nth_layer + ((gdouble) total_size)/
-                                   layer_size) / (gdouble) n_layers);
+                                  (gdouble) total_size / (gdouble) layer_size);
     }
 }
 
@@ -3234,8 +3240,6 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
   glong               total_size       = 0;
   glong               layer_size;
   gint                count            = 0;
-  gint                nth_layer        = quantobj->nth_layer;
-  gint                n_layers         = quantobj->n_layers;
 
   gimp_item_get_offset (GIMP_ITEM (layer), &offsetx, &offsety);
 
@@ -3433,8 +3437,7 @@ median_cut_pass2_fixed_dither_rgb (QuantizeObj *quantobj,
 
       if (quantobj->progress && (count % 16 == 0))
         gimp_progress_set_value (quantobj->progress,
-                                 (nth_layer + ((gdouble) total_size)/
-                                  layer_size) / (gdouble) n_layers);
+                                 (gdouble) total_size / (gdouble) layer_size);
     }
 }
 
@@ -3946,8 +3949,6 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
   gint          global_rmax = 0, global_rmin = G_MAXINT;
   gint          global_gmax = 0, global_gmin = G_MAXINT;
   gint          global_bmax = 0, global_bmin = G_MAXINT;
-  gint          nth_layer = quantobj->nth_layer;
-  gint          n_layers  = quantobj->n_layers;
 
   src_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
 
@@ -4265,8 +4266,7 @@ median_cut_pass2_fs_dither_rgb (QuantizeObj *quantobj,
 
       if (quantobj->progress && (row % 16 == 0))
         gimp_progress_set_value (quantobj->progress,
-                                 (nth_layer + ((gdouble) row) /
-                                  height) / (gdouble) n_layers);
+                                 (gdouble) row / (gdouble) height);
     }
 
   g_free (error_limiter - 255);
diff --git a/app/core/gimpimage-convert-precision.c b/app/core/gimpimage-convert-precision.c
index 0b41f74..64838ae 100644
--- a/app/core/gimpimage-convert-precision.c
+++ b/app/core/gimpimage-convert-precision.c
@@ -30,6 +30,7 @@
 
 #include "gegl/gimp-babl.h"
 
+#include "gimpchannel.h"
 #include "gimpdrawable.h"
 #include "gimpdrawable-operation.h"
 #include "gimpimage.h"
@@ -37,8 +38,8 @@
 #include "gimpimage-convert-precision.h"
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
-#include "gimpsubprogress.h"
 
 #include "text/gimptextlayer.h"
 
@@ -57,11 +58,10 @@ gimp_image_convert_precision (GimpImage        *image,
   GimpColorProfile *new_profile = NULL;
   const Babl       *old_format;
   const Babl       *new_format;
-  GList            *all_drawables;
-  GList            *list;
+  GimpObjectQueue  *queue;
+  GList            *layers;
+  GimpDrawable     *drawable;
   const gchar      *undo_desc    = NULL;
-  GimpProgress     *sub_progress = NULL;
-  gint              nth_drawable, n_drawables;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (precision != gimp_image_get_precision (image));
@@ -69,14 +69,6 @@ gimp_image_convert_precision (GimpImage        *image,
                     gimp_image_get_base_type (image) != GIMP_INDEXED);
   g_return_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress));
 
-  all_drawables = g_list_concat (gimp_image_get_layer_list (image),
-                                 gimp_image_get_channel_list (image));
-
-  n_drawables = g_list_length (all_drawables) + 1 /* + selection */;
-
-  if (progress)
-    sub_progress = gimp_sub_progress_new (progress);
-
   switch (precision)
     {
     case GIMP_PRECISION_U8_LINEAR:
@@ -120,6 +112,16 @@ gimp_image_convert_precision (GimpImage        *image,
   if (progress)
     gimp_progress_start (progress, FALSE, "%s", undo_desc);
 
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
+
+  layers = gimp_image_get_layer_list (image);
+  gimp_object_queue_push_list (queue, layers);
+  g_list_free (layers);
+
+  gimp_object_queue_push (queue, gimp_image_get_mask (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+
   g_object_freeze_notify (G_OBJECT (image));
 
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_CONVERT,
@@ -172,33 +174,46 @@ gimp_image_convert_precision (GimpImage        *image,
         new_profile = g_object_ref (old_profile);
     }
 
-  for (list = all_drawables, nth_drawable = 0;
-       list;
-       list = g_list_next (list), nth_drawable++)
+  while ((drawable = gimp_object_queue_pop (queue)))
     {
-      GimpDrawable *drawable = list->data;
-      gint          dither_type;
+      if (drawable == GIMP_DRAWABLE (gimp_image_get_mask (image)))
+        {
+          GeglBuffer *buffer;
 
-      if (gimp_item_is_text_layer (GIMP_ITEM (drawable)))
-        dither_type = text_layer_dither_type;
+          gimp_image_undo_push_mask_precision (image, NULL,
+                                               GIMP_CHANNEL (drawable));
+
+          buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                                    gimp_image_get_width  (image),
+                                                    gimp_image_get_height (image)),
+                                    gimp_image_get_mask_format (image));
+
+          gegl_buffer_copy (gimp_drawable_get_buffer (drawable), NULL,
+                            GEGL_ABYSS_NONE,
+                            buffer, NULL);
+
+          gimp_drawable_set_buffer (drawable, FALSE, NULL, buffer);
+          g_object_unref (buffer);
+        }
       else
-        dither_type = layer_dither_type;
-
-      if (sub_progress)
-        gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                    nth_drawable, n_drawables);
-
-      gimp_drawable_convert_type (drawable, image,
-                                  gimp_drawable_get_base_type (drawable),
-                                  precision,
-                                  gimp_drawable_has_alpha (drawable),
-                                  new_profile,
-                                  dither_type,
-                                  mask_dither_type,
-                                  TRUE, sub_progress);
-    }
+        {
+          gint dither_type;
 
-  g_list_free (all_drawables);
+          if (gimp_item_is_text_layer (GIMP_ITEM (drawable)))
+            dither_type = text_layer_dither_type;
+          else
+            dither_type = layer_dither_type;
+
+          gimp_drawable_convert_type (drawable, image,
+                                      gimp_drawable_get_base_type (drawable),
+                                      precision,
+                                      gimp_drawable_has_alpha (drawable),
+                                      new_profile,
+                                      dither_type,
+                                      mask_dither_type,
+                                      TRUE, progress);
+        }
+    }
 
   if (new_profile)
     {
@@ -208,42 +223,12 @@ gimp_image_convert_precision (GimpImage        *image,
       g_object_unref (new_profile);
     }
 
-  /*  convert the selection mask  */
-  {
-    GimpChannel *mask = gimp_image_get_mask (image);
-    GeglBuffer  *buffer;
-
-    if (sub_progress)
-      gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                  nth_drawable, n_drawables);
-
-    gimp_image_undo_push_mask_precision (image, NULL, mask);
-
-    buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
-                                              gimp_image_get_width  (image),
-                                              gimp_image_get_height (image)),
-                              gimp_image_get_mask_format (image));
-
-    gegl_buffer_copy (gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)), NULL,
-                      GEGL_ABYSS_NONE,
-                      buffer, NULL);
-
-    gimp_drawable_set_buffer (GIMP_DRAWABLE (mask), FALSE, NULL, buffer);
-    g_object_unref (buffer);
-
-    nth_drawable++;
-  }
-
-  if (sub_progress)
-    gimp_progress_set_value (sub_progress, 1.0);
-
   gimp_image_undo_group_end (image);
 
   gimp_image_precision_changed (image);
   g_object_thaw_notify (G_OBJECT (image));
 
-  if (sub_progress)
-    g_object_unref (sub_progress);
+  g_object_unref (queue);
 
   if (progress)
     gimp_progress_end (progress);
@@ -270,37 +255,41 @@ gimp_image_convert_dither_u8 (GimpImage    *image,
 
   if (dither)
     {
-      GList *drawables;
-      GList *list;
+      GimpObjectQueue *queue;
+      GList           *layers;
+      GList           *list;
+      GimpDrawable    *drawable;
+
+      if (progress)
+        gimp_progress_start (progress, FALSE, "%s", _("Dithering"));
 
-      drawables = gimp_image_get_layer_list (image);
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
 
-      for (list = drawables; list; list = g_list_next (list))
+      layers = gimp_image_get_layer_list (image);
+
+      for (list = layers; list; list = g_list_next (list))
         {
           if (! gimp_viewable_get_children (list->data) &&
               ! gimp_item_is_text_layer (list->data))
             {
-              gimp_drawable_apply_operation (list->data, progress,
-                                             _("Dithering"),
-                                             dither);
+              gimp_object_queue_push (queue, list->data);
             }
         }
 
-      g_list_free (drawables);
+      g_list_free (layers);
 
-      drawables = gimp_image_get_channel_list (image);
+      gimp_object_queue_push (queue, gimp_image_get_mask (image));
+      gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
 
-      for (list = drawables; list; list = g_list_next (list))
+      while ((drawable = gimp_object_queue_pop (queue)))
         {
-          if (! gimp_viewable_get_children (list->data))
-            {
-              gimp_drawable_apply_operation (list->data, progress,
-                                             _("Dithering"),
-                                             dither);
-            }
+          gimp_drawable_apply_operation (drawable, progress,
+                                         _("Dithering"),
+                                         dither);
         }
 
-      g_list_free (drawables);
+      g_object_unref (queue);
 
       g_object_unref (dither);
     }
diff --git a/app/core/gimpimage-convert-type.c b/app/core/gimpimage-convert-type.c
index efbebde..0483458 100644
--- a/app/core/gimpimage-convert-type.c
+++ b/app/core/gimpimage-convert-type.c
@@ -35,8 +35,8 @@
 #include "gimpimage-convert-type.h"
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
-#include "gimpsubprogress.h"
 
 #include "gimp-intl.h"
 
@@ -50,12 +50,10 @@ gimp_image_convert_type (GimpImage          *image,
 {
   GimpImageBaseType  old_type;
   const Babl        *new_layer_format;
+  GimpObjectQueue   *queue;
   GList             *all_layers;
-  GList             *list;
-  const gchar       *undo_desc    = NULL;
-  GimpProgress      *sub_progress = NULL;
-  gint               nth_layer;
-  gint               n_layers;
+  GimpDrawable      *drawable;
+  const gchar       *undo_desc = NULL;
 
   g_return_val_if_fail (GIMP_IS_IMAGE (image), FALSE);
   g_return_val_if_fail (new_type != gimp_image_get_base_type (image), FALSE);
@@ -93,12 +91,12 @@ gimp_image_convert_type (GimpImage          *image,
 
   gimp_set_busy (image->gimp);
 
-  all_layers = gimp_image_get_layer_list (image);
-
-  n_layers = g_list_length (all_layers);
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
 
-  if (progress)
-    sub_progress = gimp_sub_progress_new (progress);
+  all_layers = gimp_image_get_layer_list (image);
+  gimp_object_queue_push_list (queue, all_layers);
+  g_list_free (all_layers);
 
   g_object_freeze_notify (G_OBJECT (image));
 
@@ -123,23 +121,15 @@ gimp_image_convert_type (GimpImage          *image,
         dest_profile = gimp_image_get_builtin_color_profile (image);
     }
 
-  for (list = all_layers, nth_layer = 0;
-       list;
-       list = g_list_next (list), nth_layer++)
+  while ((drawable = gimp_object_queue_pop (queue)))
     {
-      GimpDrawable *drawable = list->data;
-
-      if (sub_progress)
-        gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                    nth_layer, n_layers);
-
       gimp_drawable_convert_type (drawable, image,
                                   new_type,
                                   gimp_drawable_get_precision (drawable),
                                   gimp_drawable_has_alpha (drawable),
                                   dest_profile,
                                   GEGL_DITHER_NONE, GEGL_DITHER_NONE,
-                                  TRUE, sub_progress);
+                                  TRUE, progress);
     }
 
   if (old_type == GIMP_INDEXED)
@@ -156,15 +146,12 @@ gimp_image_convert_type (GimpImage          *image,
         gimp_color_managed_profile_changed (GIMP_COLOR_MANAGED (image));
     }
 
-  if (sub_progress)
-    gimp_progress_set_value (sub_progress, 1.0);
-
   gimp_image_undo_group_end (image);
 
   gimp_image_mode_changed (image);
   g_object_thaw_notify (G_OBJECT (image));
 
-  g_list_free (all_layers);
+  g_object_unref (queue);
 
   gimp_unset_busy (image->gimp);
 
diff --git a/app/core/gimpimage-flip.c b/app/core/gimpimage-flip.c
index e4c3b87..3cddee5 100644
--- a/app/core/gimpimage-flip.c
+++ b/app/core/gimpimage-flip.c
@@ -33,6 +33,7 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimpitem.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
 #include "gimpsamplepoint.h"
 
@@ -43,10 +44,10 @@ gimp_image_flip (GimpImage           *image,
                  GimpOrientationType  flip_type,
                  GimpProgress        *progress)
 {
-  GList   *list;
-  gdouble  axis;
-  gdouble  progress_max;
-  gdouble  progress_current = 1.0;
+  GimpObjectQueue *queue;
+  GimpItem        *item;
+  GList           *list;
+  gdouble          axis;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (GIMP_IS_CONTEXT (context));
@@ -69,57 +70,22 @@ gimp_image_flip (GimpImage           *image,
       return;
     }
 
-  progress_max = (gimp_container_get_n_children (gimp_image_get_channels (image)) +
-                  gimp_container_get_n_children (gimp_image_get_layers (image))   +
-                  gimp_container_get_n_children (gimp_image_get_vectors (image))  +
-                  1 /* selection */);
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
 
-  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_FLIP, NULL);
-
-  /*  Flip all channels  */
-  for (list = gimp_image_get_channel_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_item_flip (item, context, flip_type, axis, TRUE);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Flip all vectors  */
-  for (list = gimp_image_get_vectors_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_item_flip (item, context, flip_type, axis, FALSE);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Don't forget the selection mask!  */
-  gimp_item_flip (GIMP_ITEM (gimp_image_get_mask (image)), context,
-                  flip_type, axis, TRUE);
+  gimp_object_queue_push_container (queue, gimp_image_get_layers (image));
+  gimp_object_queue_push (queue, gimp_image_get_mask (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_vectors (image));
 
-  if (progress)
-    gimp_progress_set_value (progress, progress_current++ / progress_max);
+  gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_FLIP, NULL);
 
-  /*  Flip all layers  */
-  for (list = gimp_image_get_layer_iter (image);
-       list;
-       list = g_list_next (list))
+  /*  Flip all layers, channels (including selection mask), and vectors  */
+  while ((item = gimp_object_queue_pop (queue)))
     {
-      GimpItem *item = list->data;
-
       gimp_item_flip (item, context, flip_type, axis, FALSE);
 
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
+      gimp_progress_set_value (progress, 1.0);
     }
 
   /*  Flip all Guides  */
@@ -177,5 +143,7 @@ gimp_image_flip (GimpImage           *image,
 
   gimp_image_undo_group_end (image);
 
+  g_object_unref (queue);
+
   gimp_unset_busy (image->gimp);
 }
diff --git a/app/core/gimpimage-item-list.c b/app/core/gimpimage-item-list.c
index a9019d3..4f08e13 100644
--- a/app/core/gimpimage-item-list.c
+++ b/app/core/gimpimage-item-list.c
@@ -29,6 +29,7 @@
 #include "gimpimage-item-list.h"
 #include "gimpimage-undo.h"
 #include "gimpitem.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
 
 #include "gimp-intl.h"
@@ -228,7 +229,16 @@ gimp_image_item_list_transform (GimpImage              *image,
 
   if (list)
     {
-      GList *l;
+      GimpObjectQueue *queue = NULL;
+      GList           *l;
+
+      if (progress)
+        {
+          queue    = gimp_object_queue_new (progress);
+          progress = GIMP_PROGRESS (queue);
+
+          gimp_object_queue_push_list (queue, list);
+        }
 
       if (list->next)
         {
@@ -240,10 +250,15 @@ gimp_image_item_list_transform (GimpImage              *image,
         }
 
       for (l = list; l; l = g_list_next (l))
-        gimp_item_transform (GIMP_ITEM (l->data), context,
-                             matrix, direction,
-                             interpolation_type,
-                             clip_result, progress);
+        {
+          if (queue)
+            gimp_object_queue_pop (queue);
+
+          gimp_item_transform (GIMP_ITEM (l->data), context,
+                               matrix, direction,
+                               interpolation_type,
+                               clip_result, progress);
+        }
 
       if (list->next)
         {
@@ -252,6 +267,8 @@ gimp_image_item_list_transform (GimpImage              *image,
 
           gimp_image_undo_group_end (image);
         }
+
+      g_clear_object (&queue);
     }
 }
 
diff --git a/app/core/gimpimage-resize.c b/app/core/gimpimage-resize.c
index 2011f2c..4a40e63 100644
--- a/app/core/gimpimage-resize.c
+++ b/app/core/gimpimage-resize.c
@@ -36,6 +36,7 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimplayer.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
 #include "gimpsamplepoint.h"
 
@@ -71,11 +72,11 @@ gimp_image_resize_with_layers (GimpImage    *image,
                                gboolean      resize_text_layers,
                                GimpProgress *progress)
 {
-  GList   *list;
-  GList   *resize_layers;
-  gdouble  progress_max;
-  gdouble  progress_current = 1.0;
-  gint     old_width, old_height;
+  GimpObjectQueue *queue;
+  GList           *resize_layers;
+  GList           *list;
+  GimpItem        *item;
+  gint             old_width, old_height;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (GIMP_IS_CONTEXT (context));
@@ -89,16 +90,6 @@ gimp_image_resize_with_layers (GimpImage    *image,
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_RESIZE,
                                C_("undo-type", "Resize Image"));
 
-  resize_layers = gimp_image_item_list_get_list (image,
-                                                 GIMP_ITEM_TYPE_LAYERS,
-                                                 layer_set);
-
-  progress_max = (gimp_container_get_n_children (gimp_image_get_layers (image))   +
-                  gimp_container_get_n_children (gimp_image_get_channels (image)) +
-                  gimp_container_get_n_children (gimp_image_get_vectors (image))  +
-                  g_list_length (resize_layers)                                   +
-                  1 /* selection */);
-
   old_width  = gimp_image_get_width  (image);
   old_height = gimp_image_get_height (image);
 
@@ -113,42 +104,6 @@ gimp_image_resize_with_layers (GimpImage    *image,
                 "height", new_height,
                 NULL);
 
-  /*  Resize all channels  */
-  for (list = gimp_image_get_channel_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
-                        new_width, new_height, offset_x, offset_y);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Resize all vectors  */
-  for (list = gimp_image_get_vectors_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
-                        new_width, new_height, offset_x, offset_y);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Don't forget the selection mask!  */
-  gimp_item_resize (GIMP_ITEM (gimp_image_get_mask (image)),
-                    context, GIMP_FILL_TRANSPARENT,
-                    new_width, new_height, offset_x, offset_y);
-
-  if (progress)
-    gimp_progress_set_value (progress, progress_current++ / progress_max);
-
   /*  Reposition all layers  */
   for (list = gimp_image_get_layer_iter (image);
        list;
@@ -157,17 +112,18 @@ gimp_image_resize_with_layers (GimpImage    *image,
       GimpItem *item = list->data;
 
       gimp_item_translate (item, offset_x, offset_y, TRUE);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
     }
 
-  /*  Resize all resize_layers to image size  */
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
+
+  resize_layers = gimp_image_item_list_get_list (image,
+                                                 GIMP_ITEM_TYPE_LAYERS,
+                                                 layer_set);
+
   for (list = resize_layers; list; list = g_list_next (list))
     {
       GimpItem *item = list->data;
-      gint      old_offset_x;
-      gint      old_offset_y;
 
       /*  group layers can't be resized here  */
       if (gimp_viewable_get_children (GIMP_VIEWABLE (item)))
@@ -176,17 +132,41 @@ gimp_image_resize_with_layers (GimpImage    *image,
       if (! resize_text_layers && gimp_item_is_text_layer (item))
         continue;
 
-      gimp_item_get_offset (item, &old_offset_x, &old_offset_y);
-
-      gimp_item_resize (item, context, fill_type,
-                        new_width, new_height,
-                        old_offset_x, old_offset_y);
+      gimp_item_start_move (item, TRUE);
 
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
+      gimp_object_queue_push (queue, item);
     }
 
   g_list_free (resize_layers);
+  
+  gimp_object_queue_push (queue, gimp_image_get_mask (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_vectors (image));
+
+  /*  Resize all resize_layers, channels (including selection mask), and
+   *  vectors
+   */
+  while ((item = gimp_object_queue_pop (queue)))
+    {
+      if (GIMP_IS_LAYER (item))
+        {
+          gint old_offset_x;
+          gint old_offset_y;
+
+          gimp_item_get_offset (item, &old_offset_x, &old_offset_y);
+
+          gimp_item_resize (item, context, fill_type,
+                            new_width, new_height,
+                            old_offset_x, old_offset_y);
+
+          gimp_item_end_move (item, TRUE);
+        }
+      else
+        {
+          gimp_item_resize (item, context, GIMP_FILL_TRANSPARENT,
+                            new_width, new_height, offset_x, offset_y);
+        }
+    }
 
   /*  Reposition or remove all guides  */
   list = gimp_image_get_guides (image);
@@ -254,6 +234,8 @@ gimp_image_resize_with_layers (GimpImage    *image,
                                       new_x, new_y, TRUE);
     }
 
+  g_object_unref (queue);
+
   gimp_image_undo_group_end (image);
 
   gimp_image_size_changed_detailed (image,
diff --git a/app/core/gimpimage-rotate.c b/app/core/gimpimage-rotate.c
index ac09ce1..5290ab5 100644
--- a/app/core/gimpimage-rotate.c
+++ b/app/core/gimpimage-rotate.c
@@ -22,6 +22,8 @@
 
 #include "core-types.h"
 
+#include "vectors/gimpvectors.h"
+
 #include "gimp.h"
 #include "gimpcontainer.h"
 #include "gimpcontext.h"
@@ -33,6 +35,8 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimpitem.h"
+#include "gimplayer.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
 #include "gimpsamplepoint.h"
 
@@ -54,18 +58,18 @@ gimp_image_rotate (GimpImage        *image,
                    GimpRotationType  rotate_type,
                    GimpProgress     *progress)
 {
-  GList    *list;
-  gdouble   center_x;
-  gdouble   center_y;
-  gdouble   progress_max;
-  gdouble   progress_current = 1.0;
-  gint      new_image_width;
-  gint      new_image_height;
-  gint      previous_image_width;
-  gint      previous_image_height;
-  gint      offset_x;
-  gint      offset_y;
-  gboolean  size_changed;
+  GimpObjectQueue *queue;
+  GimpItem        *item;
+  GList           *list;
+  gdouble          center_x;
+  gdouble          center_y;
+  gint             new_image_width;
+  gint             new_image_height;
+  gint             previous_image_width;
+  gint             previous_image_height;
+  gint             offset_x;
+  gint             offset_y;
+  gboolean         size_changed;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (GIMP_IS_CONTEXT (context));
@@ -77,11 +81,6 @@ gimp_image_rotate (GimpImage        *image,
   center_x              = previous_image_width  / 2.0;
   center_y              = previous_image_height / 2.0;
 
-  progress_max = (gimp_container_get_n_children (gimp_image_get_channels (image)) +
-                  gimp_container_get_n_children (gimp_image_get_layers (image))   +
-                  gimp_container_get_n_children (gimp_image_get_vectors (image))  +
-                  1 /* selection */);
-
   /*  Resize the image (if needed)  */
   switch (rotate_type)
     {
@@ -109,76 +108,48 @@ gimp_image_rotate (GimpImage        *image,
 
   gimp_set_busy (image->gimp);
 
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
+
+  gimp_object_queue_push_container (queue, gimp_image_get_layers (image));
+  gimp_object_queue_push (queue, gimp_image_get_mask (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_vectors (image));
+
   g_object_freeze_notify (G_OBJECT (image));
 
   gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_IMAGE_ROTATE, NULL);
 
-  /*  Rotate all channels  */
-  for (list = gimp_image_get_channel_iter (image);
-       list;
-       list = g_list_next (list))
+  /*  Rotate all layers, channels (including selection mask), and vectors  */
+  while ((item = gimp_object_queue_pop (queue)))
     {
-      GimpItem *item = list->data;
-
-      gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);
-
-      gimp_item_set_offset (item, 0, 0);
+      gint off_x;
+      gint off_y;
 
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Rotate all vectors  */
-  for (list = gimp_image_get_vectors_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
+      gimp_item_get_offset (item, &off_x, &off_y);
 
       gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);
 
-      gimp_item_set_offset (item, 0, 0);
-      gimp_item_set_size (item, new_image_width, new_image_height);
-
-      gimp_item_translate (item,
-                           (new_image_width  - gimp_image_get_width  (image)) / 2,
-                           (new_image_height - gimp_image_get_height (image)) / 2,
-                           FALSE);
-
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
-    }
-
-  /*  Don't forget the selection mask!  */
-  {
-    GimpChannel *mask = gimp_image_get_mask (image);
-
-    gimp_item_rotate (GIMP_ITEM (mask), context,
-                      rotate_type, center_x, center_y, FALSE);
-
-    gimp_item_set_offset (GIMP_ITEM (mask), 0, 0);
-
-    if (progress)
-      gimp_progress_set_value (progress, progress_current++ / progress_max);
-  }
-
-  /*  Rotate all layers  */
-  for (list = gimp_image_get_layer_iter (image);
-       list;
-       list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-      gint      off_x;
-      gint      off_y;
-
-      gimp_item_get_offset (item, &off_x, &off_y);
+      if (GIMP_IS_LAYER (item))
+        {
+          gimp_image_rotate_item_offset (image, rotate_type, item, off_x, off_y);
+        }
+      else
+        {
+          gimp_item_set_offset (item, 0, 0);
 
-      gimp_item_rotate (item, context, rotate_type, center_x, center_y, FALSE);
+          if (GIMP_IS_VECTORS (item))
+            {
+              gimp_item_set_size (item, new_image_width, new_image_height);
 
-      gimp_image_rotate_item_offset (image, rotate_type, item, off_x, off_y);
+              gimp_item_translate (item,
+                                   (new_image_width  - gimp_image_get_width  (image)) / 2,
+                                   (new_image_height - gimp_image_get_height (image)) / 2,
+                                   FALSE);
+            }
+        }
 
-      if (progress)
-        gimp_progress_set_value (progress, progress_current++ / progress_max);
+      gimp_progress_set_value (progress, 1.0);
     }
 
   /*  Rotate all Guides  */
@@ -229,6 +200,8 @@ gimp_image_rotate (GimpImage        *image,
 
   gimp_image_undo_group_end (image);
 
+  g_object_unref (queue);
+
   if (size_changed)
     gimp_image_size_changed_detailed (image,
                                       -offset_x,
diff --git a/app/core/gimpimage-scale.c b/app/core/gimpimage-scale.c
index fa405b0..cbc0f00 100644
--- a/app/core/gimpimage-scale.c
+++ b/app/core/gimpimage-scale.c
@@ -33,10 +33,10 @@
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
 #include "gimplayer.h"
+#include "gimpobjectqueue.h"
 #include "gimpprogress.h"
 #include "gimpprojection.h"
 #include "gimpsamplepoint.h"
-#include "gimpsubprogress.h"
 
 #include "gimp-log.h"
 #include "gimp-intl.h"
@@ -49,19 +49,15 @@ gimp_image_scale (GimpImage             *image,
                   GimpInterpolationType  interpolation_type,
                   GimpProgress          *progress)
 {
-  GimpProgress *sub_progress;
-  GList        *all_layers;
-  GList        *all_channels;
-  GList        *all_vectors;
-  GList        *list;
-  gint          old_width;
-  gint          old_height;
-  gint          offset_x;
-  gint          offset_y;
-  gdouble       img_scale_w      = 1.0;
-  gdouble       img_scale_h      = 1.0;
-  gint          progress_steps;
-  gint          progress_current = 0;
+  GimpObjectQueue *queue;
+  GimpItem        *item;
+  GList           *list;
+  gint             old_width;
+  gint             old_height;
+  gint             offset_x;
+  gint             offset_y;
+  gdouble          img_scale_w = 1.0;
+  gdouble          img_scale_h = 1.0;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
   g_return_if_fail (new_width > 0 && new_height > 0);
@@ -69,16 +65,13 @@ gimp_image_scale (GimpImage             *image,
 
   gimp_set_busy (image->gimp);
 
-  sub_progress = gimp_sub_progress_new (progress);
+  queue    = gimp_object_queue_new (progress);
+  progress = GIMP_PROGRESS (queue);
 
-  all_layers   = gimp_image_get_layer_list (image);
-  all_channels = gimp_image_get_channel_list (image);
-  all_vectors  = gimp_image_get_vectors_list (image);
-
-  progress_steps = (g_list_length (all_layers)   +
-                    g_list_length (all_channels) +
-                    g_list_length (all_vectors)  +
-                    1 /* selection */);
+  gimp_object_queue_push_container (queue, gimp_image_get_layers (image));
+  gimp_object_queue_push (queue, gimp_image_get_mask (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_channels (image));
+  gimp_object_queue_push_container (queue, gimp_image_get_vectors (image));
 
   g_object_freeze_notify (G_OBJECT (image));
 
@@ -110,73 +103,23 @@ gimp_image_scale (GimpImage             *image,
                 "height", new_height,
                 NULL);
 
-  /*  Scale all channels  */
-  for (list = all_channels; list; list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                  progress_current++, progress_steps);
-
-      gimp_item_scale (item,
-                       new_width, new_height, 0, 0,
-                       interpolation_type, sub_progress);
-    }
-
-  /*  Scale all vectors  */
-  for (list = all_vectors; list; list = g_list_next (list))
+  /*  Scale all layers, channels (including selection mask), and vectors  */
+  while ((item = gimp_object_queue_pop (queue)))
     {
-      GimpItem *item = list->data;
-
-      gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                  progress_current++, progress_steps);
-
-      gimp_item_scale (item,
-                       new_width, new_height, 0, 0,
-                       interpolation_type, sub_progress);
-    }
-
-  /*  Don't forget the selection mask!  */
-  gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                              progress_current++, progress_steps);
-
-  gimp_item_scale (GIMP_ITEM (gimp_image_get_mask (image)),
-                   new_width, new_height, 0, 0,
-                   interpolation_type, sub_progress);
-
-  /*  Scale all layers  */
-  for (list = all_layers; list; list = g_list_next (list))
-    {
-      GimpItem *item = list->data;
-
-      gimp_sub_progress_set_step (GIMP_SUB_PROGRESS (sub_progress),
-                                  progress_current++, progress_steps);
-
-      /*  group layers are updated automatically  */
-      if (gimp_viewable_get_children (GIMP_VIEWABLE (item)))
-        {
-          gimp_group_layer_suspend_resize (GIMP_GROUP_LAYER (item), FALSE);
-          continue;
-        }
-
       if (! gimp_item_scale_by_factors (item,
                                         img_scale_w, img_scale_h,
-                                        interpolation_type, sub_progress))
+                                        interpolation_type, progress))
         {
           /* Since 0 < img_scale_w, img_scale_h, failure due to one or more
            * vanishing scaled layer dimensions. Implicit delete implemented
            * here. Upstream warning implemented in resize_check_layer_scaling(),
            * which offers the user the chance to bail out.
            */
+          g_return_if_fail (GIMP_IS_LAYER (item));
           gimp_image_remove_layer (image, GIMP_LAYER (item), TRUE, NULL);
         }
     }
 
-  for (list = all_layers; list; list = g_list_next (list))
-    if (gimp_viewable_get_children (list->data))
-      gimp_group_layer_resume_resize (list->data, FALSE);
-
-
   /*  Scale all Guides  */
   for (list = gimp_image_get_guides (image);
        list;
@@ -223,11 +166,7 @@ gimp_image_scale (GimpImage             *image,
 
   gimp_image_undo_group_end (image);
 
-  g_list_free (all_layers);
-  g_list_free (all_channels);
-  g_list_free (all_vectors);
-
-  g_object_unref (sub_progress);
+  g_object_unref (queue);
 
   gimp_image_size_changed_detailed (image,
                                     -offset_x,
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index aaeee5c..fa8aba9 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -53,7 +53,9 @@
 #include "gimplayer.h"
 #include "gimplayermask.h"
 #include "gimpmarshal.h"
+#include "gimpobjectqueue.h"
 #include "gimppickable.h"
+#include "gimpprogress.h"
 
 #include "gimp-intl.h"
 
@@ -1148,17 +1150,47 @@ gimp_layer_scale (GimpItem              *item,
                   GimpInterpolationType  interpolation_type,
                   GimpProgress          *progress)
 {
-  GimpLayer *layer = GIMP_LAYER (item);
+  GimpLayer       *layer = GIMP_LAYER (item);
+  GimpObjectQueue *queue = NULL;
+
+  if (progress && layer->mask)
+    {
+      GimpLayerMask *mask;
+
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
+
+      /* temporarily set layer->mask to NULL, so that its size won't be counted
+       * when pushing the layer to the queue.
+       */
+      mask        = layer->mask;
+      layer->mask = NULL;
+
+      gimp_object_queue_push (queue, layer);
+      gimp_object_queue_push (queue, mask);
+
+      layer->mask = mask;
+    }
+
+  if (queue)
+    gimp_object_queue_pop (queue);
 
   GIMP_LAYER_GET_CLASS (layer)->scale (layer, new_width, new_height,
                                        new_offset_x, new_offset_y,
                                        interpolation_type, progress);
 
   if (layer->mask)
-    gimp_item_scale (GIMP_ITEM (layer->mask),
-                     new_width, new_height,
-                     new_offset_x, new_offset_y,
-                     interpolation_type, progress);
+    {
+      if (queue)
+        gimp_object_queue_pop (queue);
+
+      gimp_item_scale (GIMP_ITEM (layer->mask),
+                       new_width, new_height,
+                       new_offset_x, new_offset_y,
+                       interpolation_type, progress);
+    }
+
+  g_clear_object (&queue);
 }
 
 static void
@@ -1226,7 +1258,30 @@ gimp_layer_transform (GimpItem               *item,
                       GimpTransformResize     clip_result,
                       GimpProgress           *progress)
 {
-  GimpLayer *layer = GIMP_LAYER (item);
+  GimpLayer       *layer = GIMP_LAYER (item);
+  GimpObjectQueue *queue = NULL;
+
+  if (progress && layer->mask)
+    {
+      GimpLayerMask *mask;
+
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
+
+      /* temporarily set layer->mask to NULL, so that its size won't be counted
+       * when pushing the layer to the queue.
+       */
+      mask        = layer->mask;
+      layer->mask = NULL;
+
+      gimp_object_queue_push (queue, layer);
+      gimp_object_queue_push (queue, mask);
+
+      layer->mask = mask;
+    }
+
+  if (queue)
+    gimp_object_queue_pop (queue);
 
   GIMP_LAYER_GET_CLASS (layer)->transform (layer, context, matrix, direction,
                                            interpolation_type,
@@ -1234,10 +1289,17 @@ gimp_layer_transform (GimpItem               *item,
                                            progress);
 
   if (layer->mask)
-    gimp_item_transform (GIMP_ITEM (layer->mask), context,
-                         matrix, direction,
-                         interpolation_type,
-                         clip_result, progress);
+    {
+      if (queue)
+        gimp_object_queue_pop (queue);
+
+      gimp_item_transform (GIMP_ITEM (layer->mask), context,
+                           matrix, direction,
+                           interpolation_type,
+                           clip_result, progress);
+    }
+
+  g_clear_object (&queue);
 }
 
 static void
@@ -1300,25 +1362,56 @@ gimp_layer_convert_type (GimpDrawable     *drawable,
                          gboolean          push_undo,
                          GimpProgress     *progress)
 {
-  GimpLayer *layer = GIMP_LAYER (drawable);
+  GimpLayer       *layer = GIMP_LAYER (drawable);
+  GimpObjectQueue *queue = NULL;
+  gboolean         convert_mask;
+
+  convert_mask = layer->mask &&
+                 gimp_babl_format_get_precision (new_format) !=
+                 gimp_drawable_get_precision (GIMP_DRAWABLE (layer->mask));
+
+  if (progress && convert_mask)
+    {
+      GimpLayerMask *mask;
+
+      queue    = gimp_object_queue_new (progress);
+      progress = GIMP_PROGRESS (queue);
+
+      /* temporarily set layer->mask to NULL, so that its size won't be counted
+       * when pushing the layer to the queue.
+       */
+      mask        = layer->mask;
+      layer->mask = NULL;
+
+      gimp_object_queue_push (queue, layer);
+      gimp_object_queue_push (queue, mask);
+
+      layer->mask = mask;
+    }
+
+  if (queue)
+    gimp_object_queue_pop (queue);
 
   GIMP_LAYER_GET_CLASS (layer)->convert_type (layer, dest_image, new_format,
                                               dest_profile, layer_dither_type,
                                               mask_dither_type, push_undo,
                                               progress);
 
-  if (layer->mask &&
-      gimp_babl_format_get_precision (new_format) !=
-      gimp_drawable_get_precision (GIMP_DRAWABLE (layer->mask)))
+  if (convert_mask)
     {
+      if (queue)
+        gimp_object_queue_pop (queue);
+
       gimp_drawable_convert_type (GIMP_DRAWABLE (layer->mask), dest_image,
                                   GIMP_GRAY,
                                   gimp_babl_format_get_precision (new_format),
                                   gimp_drawable_has_alpha (GIMP_DRAWABLE (layer->mask)),
                                   NULL,
                                   layer_dither_type, mask_dither_type,
-                                  push_undo, NULL);
+                                  push_undo, progress);
     }
+
+  g_clear_object (&queue);
 }
 
 static void


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