[gimp/gimp-2-10] app: compute line art in advance.



commit 32f0a49ecc0f44540ebd4bf99d7ae9c78d9d4d39
Author: Jehan <jehan girinstud io>
Date:   Sat Nov 3 18:40:50 2018 +0100

    app: compute line art in advance.
    
    Right now, this is mostly meaningless as it is still done sequentially.
    But I am mostly preparing the field to pre-compute the line art as
    background thread.
    
    (cherry picked from commit f246f404940d7e2e54ea2a863b38970b86e198cc)

 app/core/gimpchannel-select.c             |   1 +
 app/core/gimpdrawable-bucket-fill.c       |   2 +
 app/core/gimpdrawable-bucket-fill.h       |   1 +
 app/core/gimppickable-contiguous-region.c | 201 ++++++++++++++--------
 app/core/gimppickable-contiguous-region.h |  31 ++--
 app/pdb/drawable-edit-cmds.c              |   2 +-
 app/tools/gimpbucketfilltool.c            | 270 ++++++++++++++++++++++++++++--
 app/tools/gimpbucketfilltool.h            |   5 +-
 app/tools/gimpfuzzyselecttool.c           |   2 +-
 pdb/groups/drawable_edit.pdb              |   2 +-
 10 files changed, 421 insertions(+), 96 deletions(-)
---
diff --git a/app/core/gimpchannel-select.c b/app/core/gimpchannel-select.c
index e0cfc27354..dd6c433aee 100644
--- a/app/core/gimpchannel-select.c
+++ b/app/core/gimpchannel-select.c
@@ -516,6 +516,7 @@ gimp_channel_select_fuzzy (GimpChannel         *channel,
     pickable = GIMP_PICKABLE (drawable);
 
   add_on = gimp_pickable_contiguous_region_by_seed (pickable,
+                                                    NULL,
                                                     antialias,
                                                     threshold,
                                                     select_transparent,
diff --git a/app/core/gimpdrawable-bucket-fill.c b/app/core/gimpdrawable-bucket-fill.c
index a1a181eeb9..b5e6d7d484 100644
--- a/app/core/gimpdrawable-bucket-fill.c
+++ b/app/core/gimpdrawable-bucket-fill.c
@@ -49,6 +49,7 @@
 
 void
 gimp_drawable_bucket_fill (GimpDrawable         *drawable,
+                           GeglBuffer           *line_art,
                            GimpFillOptions      *options,
                            gboolean              fill_transparent,
                            GimpSelectCriterion   fill_criterion,
@@ -91,6 +92,7 @@ gimp_drawable_bucket_fill (GimpDrawable         *drawable,
    *  contiguous region.
    */
   mask_buffer = gimp_pickable_contiguous_region_by_seed (pickable,
+                                                         line_art,
                                                          antialias,
                                                          threshold,
                                                          fill_transparent,
diff --git a/app/core/gimpdrawable-bucket-fill.h b/app/core/gimpdrawable-bucket-fill.h
index f79062a8fb..a614fb727d 100644
--- a/app/core/gimpdrawable-bucket-fill.h
+++ b/app/core/gimpdrawable-bucket-fill.h
@@ -20,6 +20,7 @@
 
 
 void   gimp_drawable_bucket_fill (GimpDrawable        *drawable,
+                                  GeglBuffer          *line_art,
                                   GimpFillOptions     *options,
                                   gboolean             fill_transparent,
                                   GimpSelectCriterion  fill_criterion,
diff --git a/app/core/gimppickable-contiguous-region.c b/app/core/gimppickable-contiguous-region.c
index d12878e631..d4c06a75a3 100644
--- a/app/core/gimppickable-contiguous-region.c
+++ b/app/core/gimppickable-contiguous-region.c
@@ -98,8 +98,103 @@ static void     find_contiguous_region    (GeglBuffer          *src_buffer,
 
 /*  public functions  */
 
+GeglBuffer *
+gimp_pickable_contiguous_region_prepare_line_art (GimpPickable *pickable,
+                                                  gboolean      select_transparent)
+{
+  GeglBuffer *lineart;
+  gboolean    has_alpha;
+
+  g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
+
+  gimp_pickable_flush (pickable);
+
+  lineart = gimp_pickable_get_buffer (pickable);
+  has_alpha = babl_format_has_alpha (gegl_buffer_get_format (lineart));
+
+  if (! has_alpha)
+    {
+      if (select_transparent)
+        {
+          /*  don't select transparent regions if there are no fully
+           *  transparent pixels.
+           */
+          GeglBufferIterator *gi;
+
+          select_transparent = FALSE;
+          gi = gegl_buffer_iterator_new (lineart, NULL, 0, babl_format ("A u8"),
+                                         GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 3);
+          while (gegl_buffer_iterator_next (gi))
+            {
+              guint8 *p = (guint8*) gi->items[0].data;
+              gint    k;
+
+              for (k = 0; k < gi->length; k++)
+                {
+                  if (! *p)
+                    {
+                      select_transparent = TRUE;
+                      break;
+                    }
+                  p++;
+                }
+              if (select_transparent)
+                break;
+            }
+          if (select_transparent)
+            gegl_buffer_iterator_stop (gi);
+        }
+    }
+  else
+    {
+      select_transparent = FALSE;
+    }
+
+  /* For smart selection, we generate a binarized image with close
+   * regions, then run a composite selection with no threshold on
+   * this intermediate buffer.
+   */
+  GIMP_TIMER_START();
+
+  lineart = gimp_lineart_close (lineart,
+                                select_transparent,
+                                /*contour_detection_level,*/
+                                0.92,
+                                /* erosion, */
+                                -1,
+                                /*minimal_lineart_area,*/
+                                5,
+                                /*normal_estimate_mask_size,*/
+                                5,
+                                /*end_point_rate,*/
+                                0.85,
+                                /*spline_max_length,*/
+                                60,
+                                /*spline_max_angle,*/
+                                90.0,
+                                /*end_point_connectivity,*/
+                                2,
+                                /*spline_roundness,*/
+                                1.0,
+                                /*allow_self_intersections,*/
+                                TRUE,
+                                /*created_regions_significant_area,*/
+                                4,
+                                /*created_regions_minimum_area,*/
+                                100,
+                                /*small_segments_from_spline_sources,*/
+                                TRUE,
+                                /*segments_max_length*/
+                                20);
+
+  GIMP_TIMER_END("close line-art");
+
+  return lineart;
+}
+
 GeglBuffer *
 gimp_pickable_contiguous_region_by_seed (GimpPickable        *pickable,
+                                         GeglBuffer          *line_art,
                                          gboolean             antialias,
                                          gfloat               threshold,
                                          gboolean             select_transparent,
@@ -115,89 +210,61 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable        *pickable,
   gint           n_components;
   gboolean       has_alpha;
   gfloat         start_col[MAX_CHANNELS];
+  gfloat         flag           = 2.0;
   gboolean       smart_line_art = FALSE;
-  gfloat         flag = 2.0;
+  gboolean       free_line_art  = FALSE;
 
   g_return_val_if_fail (GIMP_IS_PICKABLE (pickable), NULL);
 
-  gimp_pickable_flush (pickable);
-
-  src_buffer = gimp_pickable_get_buffer (pickable);
-
-  format = choose_format (src_buffer, select_criterion,
-                          &n_components, &has_alpha);
-
-  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
-                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
-
-  if (has_alpha)
+  if (select_criterion == GIMP_SELECT_CRITERION_LINE_ART)
     {
-      if (select_transparent)
+      if (line_art == NULL)
         {
-          /*  don't select transparent regions if the start pixel isn't
-           *  fully transparent
+          /* It is much better experience to pre-compute the line art,
+           * but it may not be always possible (for instance when
+           * selecting/filling through a PDB call).
            */
-          if (start_col[n_components - 1] > 0)
-            select_transparent = FALSE;
+          line_art      = gimp_pickable_contiguous_region_prepare_line_art (pickable, select_transparent);
+          free_line_art = TRUE;
         }
-    }
-  else
-    {
-      select_transparent = FALSE;
-    }
 
-  if (select_criterion == GIMP_SELECT_CRITERION_LINE_ART)
-    {
-      /* For smart selection, we generate a binarized image with close
-       * regions, then run a composite selection with no threshold on
-       * this intermediate buffer.
-       */
-      GIMP_TIMER_START();
-      src_buffer = gimp_lineart_close (src_buffer,
-                                       select_transparent,
-                                       /*contour_detection_level,*/
-                                       0.92,
-                                       /* erosion, */
-                                       -1,
-                                       /*minimal_lineart_area,*/
-                                       5,
-                                       /*normal_estimate_mask_size,*/
-                                       5,
-                                       /*end_point_rate,*/
-                                       0.85,
-                                       /*spline_max_length,*/
-                                       60,
-                                       /*spline_max_angle,*/
-                                       90.0,
-                                       /*end_point_connectivity,*/
-                                       2,
-                                       /*spline_roundness,*/
-                                       1.0,
-                                       /*allow_self_intersections,*/
-                                       TRUE,
-                                       /*created_regions_significant_area,*/
-                                       4,
-                                       /*created_regions_minimum_area,*/
-                                       100,
-                                       /*small_segments_from_spline_sources,*/
-                                       TRUE,
-                                       /*segments_max_length*/
-                                       20);
+      src_buffer = line_art;
+
       smart_line_art     = TRUE;
       antialias          = FALSE;
       threshold          = 0.0;
       select_transparent = FALSE;
       select_criterion   = GIMP_SELECT_CRITERION_COMPOSITE;
       diagonal_neighbors = FALSE;
+    }
+  else
+    {
+      gimp_pickable_flush (pickable);
+      src_buffer = gimp_pickable_get_buffer (pickable);
 
-      format = choose_format (src_buffer, select_criterion,
-                              &n_components, &has_alpha);
-      gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
-                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
-
-      GIMP_TIMER_END("close line-art");
+      if (has_alpha)
+        {
+          if (select_transparent)
+            {
+              /*  don't select transparent regions if the start pixel isn't
+               *  fully transparent
+               */
+              if (start_col[n_components - 1] > 0)
+                select_transparent = FALSE;
+            }
+        }
+      else
+        {
+          select_transparent = FALSE;
+        }
     }
 
+  format = choose_format (src_buffer, select_criterion,
+                          &n_components, &has_alpha);
+
+  gegl_buffer_sample (src_buffer, x, y, NULL, start_col, format,
+                      GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
+
   extent = *gegl_buffer_get_extent (src_buffer);
 
   mask_buffer = gegl_buffer_new (&extent, babl_format ("Y float"));
@@ -271,7 +338,6 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable        *pickable,
               prio++;
             }
         }
-      g_object_unref (src_buffer);
 
       /* Watershed the line art. */
       graph = gegl_node_new ();
@@ -297,6 +363,9 @@ gimp_pickable_contiguous_region_by_seed (GimpPickable        *pickable,
       g_object_unref (priomap);
 
       GIMP_TIMER_END("watershed line art");
+
+      if (free_line_art)
+        g_object_unref (src_buffer);
     }
 
   return mask_buffer;
diff --git a/app/core/gimppickable-contiguous-region.h b/app/core/gimppickable-contiguous-region.h
index 6db86248bb..7f8d693d92 100644
--- a/app/core/gimppickable-contiguous-region.h
+++ b/app/core/gimppickable-contiguous-region.h
@@ -19,21 +19,24 @@
 #define __GIMP_PICKABLE_CONTIGUOUS_REGION_H__
 
 
-GeglBuffer * gimp_pickable_contiguous_region_by_seed  (GimpPickable        *pickable,
-                                                       gboolean             antialias,
-                                                       gfloat               threshold,
-                                                       gboolean             select_transparent,
-                                                       GimpSelectCriterion  select_criterion,
-                                                       gboolean             diagonal_neighbors,
-                                                       gint                 x,
-                                                       gint                 y);
+GeglBuffer * gimp_pickable_contiguous_region_prepare_line_art (GimpPickable        *pickable,
+                                                               gboolean             select_transparent);
+GeglBuffer * gimp_pickable_contiguous_region_by_seed          (GimpPickable        *pickable,
+                                                               GeglBuffer          *line_art,
+                                                               gboolean             antialias,
+                                                               gfloat               threshold,
+                                                               gboolean             select_transparent,
+                                                               GimpSelectCriterion  select_criterion,
+                                                               gboolean             diagonal_neighbors,
+                                                               gint                 x,
+                                                               gint                 y);
 
-GeglBuffer * gimp_pickable_contiguous_region_by_color (GimpPickable        *pickable,
-                                                       gboolean             antialias,
-                                                       gfloat               threshold,
-                                                       gboolean             select_transparent,
-                                                       GimpSelectCriterion  select_criterion,
-                                                       const GimpRGB       *color);
+GeglBuffer * gimp_pickable_contiguous_region_by_color         (GimpPickable        *pickable,
+                                                               gboolean             antialias,
+                                                               gfloat               threshold,
+                                                               gboolean             select_transparent,
+                                                               GimpSelectCriterion  select_criterion,
+                                                               const GimpRGB       *color);
 
 
 #endif  /*  __GIMP_PICKABLE_CONTIGUOUS_REGION_H__ */
diff --git a/app/pdb/drawable-edit-cmds.c b/app/pdb/drawable-edit-cmds.c
index 43ac00a7e6..a5212bb1cd 100644
--- a/app/pdb/drawable-edit-cmds.c
+++ b/app/pdb/drawable-edit-cmds.c
@@ -165,7 +165,7 @@ drawable_edit_bucket_fill_invoker (GimpProcedure         *procedure,
           if (gimp_fill_options_set_by_fill_type (options, context,
                                                   fill_type, error))
             {
-              gimp_drawable_bucket_fill (drawable, options,
+              gimp_drawable_bucket_fill (drawable, NULL, options,
                                          GIMP_PDB_CONTEXT (context)->sample_transparent,
                                          GIMP_PDB_CONTEXT (context)->sample_criterion,
                                          GIMP_PDB_CONTEXT (context)->sample_threshold,
diff --git a/app/tools/gimpbucketfilltool.c b/app/tools/gimpbucketfilltool.c
index ee55344ab6..41a0f95825 100644
--- a/app/tools/gimpbucketfilltool.c
+++ b/app/tools/gimpbucketfilltool.c
@@ -31,6 +31,9 @@
 #include "core/gimpfilloptions.h"
 #include "core/gimpimage.h"
 #include "core/gimpitem.h"
+#include "core/gimplineart.h"
+#include "core/gimppickable.h"
+#include "core/gimppickable-contiguous-region.h"
 
 #include "widgets/gimphelp-ids.h"
 #include "widgets/gimpwidgets-utils.h"
@@ -45,8 +48,18 @@
 #include "gimp-intl.h"
 
 
+struct _GimpBucketFillToolPrivate
+{
+  GeglBuffer *line_art;
+  GWeakRef    cached_image;
+  GWeakRef    cached_drawable;
+};
+
 /*  local function prototypes  */
 
+static void gimp_bucket_fill_tool_constructed (GObject *object);
+static void gimp_bucket_fill_tool_finalize (GObject *object);
+
 static gboolean gimp_bucket_fill_tool_initialize   (GimpTool              *tool,
                                                     GimpDisplay           *display,
                                                     GError               **error);
@@ -66,8 +79,25 @@ static void   gimp_bucket_fill_tool_cursor_update  (GimpTool              *tool,
                                                     GdkModifierType        state,
                                                     GimpDisplay           *display);
 
-
-G_DEFINE_TYPE (GimpBucketFillTool, gimp_bucket_fill_tool, GIMP_TYPE_TOOL)
+static void     gimp_bucket_fill_compute_line_art      (GimpBucketFillTool    *tool);
+static gboolean gimp_bucket_fill_tool_connect_handlers (gpointer               data);
+static void     gimp_bucket_fill_tool_options_notified (GimpBucketFillOptions *options,
+                                                        GParamSpec            *pspec,
+                                                        GimpBucketFillTool    *tool);
+static void     gimp_bucket_fill_tool_image_changed    (GimpContext           *context,
+                                                        GimpImage             *image,
+                                                        GimpBucketFillTool    *tool);
+static void     gimp_bucket_fill_tool_drawable_changed (GimpImage            *image,
+                                                        GimpBucketFillTool   *tool);
+static void     gimp_bucket_fill_tool_drawable_update  (GimpDrawable         *drawable,
+                                                        gint                  x,
+                                                        gint                  y,
+                                                        gint                  width,
+                                                        gint                  height,
+                                                        GimpBucketFillTool   *tool);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpBucketFillTool, gimp_bucket_fill_tool, GIMP_TYPE_TOOL)
 
 #define parent_class gimp_bucket_fill_tool_parent_class
 
@@ -96,7 +126,11 @@ gimp_bucket_fill_tool_register (GimpToolRegisterCallback  callback,
 static void
 gimp_bucket_fill_tool_class_init (GimpBucketFillToolClass *klass)
 {
-  GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
+  GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+  GimpToolClass *tool_class   = GIMP_TOOL_CLASS (klass);
+
+  object_class->constructed  = gimp_bucket_fill_tool_constructed;
+  object_class->finalize     = gimp_bucket_fill_tool_finalize;
 
   tool_class->initialize     = gimp_bucket_fill_tool_initialize;
   tool_class->button_release = gimp_bucket_fill_tool_button_release;
@@ -117,6 +151,58 @@ gimp_bucket_fill_tool_init (GimpBucketFillTool *bucket_fill_tool)
                                          "context/context-opacity-set");
   gimp_tool_control_set_action_object_1 (tool->control,
                                          "context/context-pattern-select-set");
+
+  bucket_fill_tool->priv = gimp_bucket_fill_tool_get_instance_private (bucket_fill_tool);
+}
+
+static void
+gimp_bucket_fill_tool_constructed (GObject *object)
+{
+  GimpTool              *tool    = GIMP_TOOL (object);
+  GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (object);
+  Gimp                  *gimp    = GIMP_CONTEXT (options)->gimp;
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  /* Avoid computing initial line art several times (for every option
+   * property as it gets deserialized) if tool is selected when starting
+   * GIMP with an image.
+   */
+  if (gimp_is_restored (gimp))
+    gimp_bucket_fill_tool_connect_handlers (tool);
+  else
+    g_idle_add (gimp_bucket_fill_tool_connect_handlers, tool);
+}
+
+static void
+gimp_bucket_fill_tool_finalize (GObject *object)
+{
+  GimpBucketFillTool    *tool     = GIMP_BUCKET_FILL_TOOL (object);
+  GimpBucketFillOptions *options  = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool);
+  Gimp                  *gimp     = GIMP_CONTEXT (options)->gimp;
+  GimpContext           *context  = gimp_get_user_context (gimp);
+  GimpImage             *image    = g_weak_ref_get (&tool->priv->cached_image);
+  GimpDrawable          *drawable = g_weak_ref_get (&tool->priv->cached_drawable);
+
+  g_clear_object (&tool->priv->line_art);
+
+  if (image)
+    {
+      g_signal_handlers_disconnect_by_data (image, tool);
+      g_object_unref (image);
+    }
+  if (drawable)
+    {
+      g_signal_handlers_disconnect_by_data (drawable, tool);
+      g_object_unref (drawable);
+    }
+
+  g_signal_handlers_disconnect_by_func (options,
+                                        G_CALLBACK (gimp_bucket_fill_tool_options_notified),
+                                        tool);
+  g_signal_handlers_disconnect_by_data (context, tool);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
 static gboolean
@@ -124,8 +210,19 @@ gimp_bucket_fill_tool_initialize (GimpTool     *tool,
                                   GimpDisplay  *display,
                                   GError      **error)
 {
-  GimpImage    *image    = gimp_display_get_image (display);
-  GimpDrawable *drawable = gimp_image_get_active_drawable (image);
+  GimpBucketFillTool    *bucket_tool = GIMP_BUCKET_FILL_TOOL (tool);
+  GimpBucketFillOptions *options     = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (bucket_tool);
+  GimpImage             *image       = gimp_display_get_image (display);
+  GimpDrawable          *drawable    = gimp_image_get_active_drawable (image);
+
+  if (options->fill_criterion == GIMP_SELECT_CRITERION_LINE_ART)
+    {
+      GimpImage    *prev_image = g_weak_ref_get (&bucket_tool->priv->cached_image);
+      GimpDrawable *prev_drawable = g_weak_ref_get (&bucket_tool->priv->cached_drawable);
+      g_return_val_if_fail (image == prev_image && drawable == prev_drawable, FALSE);
+      g_object_unref (prev_drawable);
+      g_object_unref (prev_image);
+    }
 
   if (! GIMP_TOOL_CLASS (parent_class)->initialize (tool, display, error))
     {
@@ -139,19 +236,19 @@ gimp_bucket_fill_tool_initialize (GimpTool     *tool,
       return FALSE;
     }
 
-  if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
+  if (! gimp_item_is_visible (GIMP_ITEM (drawable)))
     {
       g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                           _("The active layer's pixels are locked."));
-      if (error)
-        gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
+                           _("The active layer is not visible."));
       return FALSE;
     }
 
-  if (! gimp_item_is_visible (GIMP_ITEM (drawable)))
+  if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
     {
       g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
-                           _("The active layer is not visible."));
+                           _("The active layer's pixels are locked."));
+      if (error)
+        gimp_tools_blink_lock_box (display->gimp, GIMP_ITEM (drawable));
       return FALSE;
     }
 
@@ -211,7 +308,10 @@ gimp_bucket_fill_tool_button_release (GimpTool              *tool,
                   y -= off_y;
                 }
 
-              gimp_drawable_bucket_fill (drawable, fill_options,
+
+              gimp_drawable_bucket_fill (drawable,
+                                         GIMP_BUCKET_FILL_TOOL (tool)->priv->line_art,
+                                         fill_options,
                                          options->fill_transparent,
                                          options->fill_criterion,
                                          options->threshold / 255.0,
@@ -310,3 +410,149 @@ gimp_bucket_fill_tool_cursor_update (GimpTool         *tool,
 
   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
 }
+
+static void
+gimp_bucket_fill_compute_line_art (GimpBucketFillTool *tool)
+{
+  GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool);
+
+  g_clear_object (&tool->priv->line_art);
+  if (options->fill_criterion == GIMP_SELECT_CRITERION_LINE_ART)
+    {
+      GimpPickable *pickable = NULL;
+      GimpDrawable *image    = g_weak_ref_get (&tool->priv->cached_image);
+      GimpDrawable *drawable = g_weak_ref_get (&tool->priv->cached_drawable);
+
+      if (image && options->sample_merged)
+        pickable = GIMP_PICKABLE (image);
+      else if (drawable && ! options->sample_merged)
+        pickable = GIMP_PICKABLE (drawable);
+
+      if (pickable)
+        tool->priv->line_art = gimp_pickable_contiguous_region_prepare_line_art (pickable,
+                                                                                 options->fill_transparent);
+      if (image)
+        g_object_unref (image);
+      if (drawable)
+        g_object_unref (drawable);
+    }
+}
+
+static gboolean
+gimp_bucket_fill_tool_connect_handlers (gpointer data)
+{
+  GimpBucketFillTool    *tool    = GIMP_BUCKET_FILL_TOOL (data);
+  GimpBucketFillOptions *options = GIMP_BUCKET_FILL_TOOL_GET_OPTIONS (tool);
+  Gimp                  *gimp    = GIMP_CONTEXT (options)->gimp;
+
+  if (gimp_is_restored (gimp))
+    {
+      GimpContext *context = gimp_get_user_context (gimp);
+      GimpImage   *image   = gimp_context_get_image (context);
+
+      g_signal_connect (options, "notify::fill-criterion",
+                        G_CALLBACK (gimp_bucket_fill_tool_options_notified),
+                        tool);
+      g_signal_connect (options, "notify::sample-merged",
+                        G_CALLBACK (gimp_bucket_fill_tool_options_notified),
+                        tool);
+      g_signal_connect (options, "notify::fill-transparent",
+                        G_CALLBACK (gimp_bucket_fill_tool_options_notified),
+                        tool);
+
+      g_signal_connect (context, "image-changed",
+                        G_CALLBACK (gimp_bucket_fill_tool_image_changed),
+                        tool);
+      gimp_bucket_fill_tool_image_changed (context, image, GIMP_BUCKET_FILL_TOOL (tool));
+
+      return G_SOURCE_REMOVE;
+    }
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+gimp_bucket_fill_tool_options_notified (GimpBucketFillOptions *options,
+                                        GParamSpec            *pspec,
+                                        GimpBucketFillTool    *tool)
+{
+  if ((! strcmp (pspec->name, "fill-criterion")   ||
+       ! strcmp (pspec->name, "fill-transparent") ||
+       ! strcmp (pspec->name, "sample-merged")) &&
+      options->fill_criterion == GIMP_SELECT_CRITERION_LINE_ART)
+    {
+      gimp_bucket_fill_compute_line_art (tool);
+    }
+}
+
+static void
+gimp_bucket_fill_tool_image_changed (GimpContext        *context,
+                                     GimpImage          *image,
+                                     GimpBucketFillTool *tool)
+{
+  GimpImage *prev_image = g_weak_ref_get (&tool->priv->cached_image);
+
+  if (image != prev_image)
+    {
+      GimpImage *prev_drawable = g_weak_ref_get (&tool->priv->cached_drawable);
+
+      g_clear_object (&tool->priv->line_art);
+
+      if (prev_image)
+        g_signal_handlers_disconnect_by_data (prev_image, tool);
+      if (prev_drawable)
+        {
+          g_signal_handlers_disconnect_by_data (prev_drawable, tool);
+          g_object_unref (prev_drawable);
+        }
+
+      g_weak_ref_set (&tool->priv->cached_image, image ? image : NULL);
+      g_weak_ref_set (&tool->priv->cached_drawable, NULL);
+      if (image)
+        {
+          g_signal_connect (image, "active-layer-changed",
+                            G_CALLBACK (gimp_bucket_fill_tool_drawable_changed),
+                            tool);
+          g_signal_connect (image, "active-channel-changed",
+                            G_CALLBACK (gimp_bucket_fill_tool_drawable_changed),
+                            tool);
+          gimp_bucket_fill_tool_drawable_changed (image, tool);
+        }
+    }
+  if (prev_image)
+    g_object_unref (prev_image);
+}
+
+static void
+gimp_bucket_fill_tool_drawable_changed (GimpImage          *image,
+                                        GimpBucketFillTool *tool)
+{
+  GimpDrawable *drawable      = gimp_image_get_active_drawable (image);
+  GimpDrawable *prev_drawable = g_weak_ref_get (&tool->priv->cached_drawable);
+
+  if (drawable != prev_drawable)
+    {
+      if (prev_drawable)
+        g_signal_handlers_disconnect_by_data (prev_drawable, tool);
+
+      g_weak_ref_set (&tool->priv->cached_drawable, drawable ? drawable : NULL);
+      if (drawable)
+        g_signal_connect (drawable, "update",
+                          G_CALLBACK (gimp_bucket_fill_tool_drawable_update),
+                          tool);
+
+      gimp_bucket_fill_compute_line_art (tool);
+    }
+  if (prev_drawable)
+    g_object_unref (prev_drawable);
+}
+
+static void
+gimp_bucket_fill_tool_drawable_update (GimpDrawable       *drawable,
+                                       gint                x,
+                                       gint                y,
+                                       gint                width,
+                                       gint                height,
+                                       GimpBucketFillTool *tool)
+{
+  gimp_bucket_fill_compute_line_art (tool);
+}
diff --git a/app/tools/gimpbucketfilltool.h b/app/tools/gimpbucketfilltool.h
index 8ce8eb02f1..0b7b8279c0 100644
--- a/app/tools/gimpbucketfilltool.h
+++ b/app/tools/gimpbucketfilltool.h
@@ -34,10 +34,13 @@
 
 typedef struct _GimpBucketFillTool      GimpBucketFillTool;
 typedef struct _GimpBucketFillToolClass GimpBucketFillToolClass;
+typedef struct _GimpBucketFillToolPrivate GimpBucketFillToolPrivate;
 
 struct _GimpBucketFillTool
 {
-  GimpTool  parent_instance;
+  GimpTool                   parent_instance;
+
+  GimpBucketFillToolPrivate *priv;
 };
 
 struct _GimpBucketFillToolClass
diff --git a/app/tools/gimpfuzzyselecttool.c b/app/tools/gimpfuzzyselecttool.c
index 785804a27b..b3eee7d196 100644
--- a/app/tools/gimpfuzzyselecttool.c
+++ b/app/tools/gimpfuzzyselecttool.c
@@ -122,7 +122,7 @@ gimp_fuzzy_select_tool_get_mask (GimpRegionSelectTool *region_select,
       pickable = GIMP_PICKABLE (image);
     }
 
-  return gimp_pickable_contiguous_region_by_seed (pickable,
+  return gimp_pickable_contiguous_region_by_seed (pickable, NULL,
                                                   sel_options->antialias,
                                                   options->threshold / 255.0,
                                                   options->select_transparent,
diff --git a/pdb/groups/drawable_edit.pdb b/pdb/groups/drawable_edit.pdb
index 52ab64b6e5..79b8c395c5 100644
--- a/pdb/groups/drawable_edit.pdb
+++ b/pdb/groups/drawable_edit.pdb
@@ -169,7 +169,7 @@ HELP
       if (gimp_fill_options_set_by_fill_type (options, context,
                                               fill_type, error))
         {
-          gimp_drawable_bucket_fill (drawable, options,
+          gimp_drawable_bucket_fill (drawable, NULL, options,
                                      GIMP_PDB_CONTEXT (context)->sample_transparent,
                                      GIMP_PDB_CONTEXT (context)->sample_criterion,
                                      GIMP_PDB_CONTEXT (context)->sample_threshold,


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