[gimp] app: exclude invisible filters from filter-stack graph



commit e02cb6adfeb9e9ceabb209c72148e8728b4845ee
Author: Ell <ell_se yahoo com>
Date:   Tue Dec 5 14:30:01 2017 -0500

    app: exclude invisible filters from filter-stack graph
    
    Currently, when a GimpFilter's visibility changes, we rely on its
    various visibility-changed signal handlers to rewire the filter
    node's graph to reflect the change.  This has two main
    disadvantages:
    
      - There's no easy, generic way to toggle a filter's  effect,
        especially one that is not subclassed, since GimpFilter only
        takes care of the case where visibility becomes FALSE, and does
        nothing by itself when it becomes TRUE again.
    
      - While GimpDrawable does handle the visibility => TRUE case, it
        doesn't disconnect the filter's input from its mode and
        (potentially) source nodes when it becomes invisible.  As a
        result, while none of the drawable's graph is processed as part
        of the composition when not visible, the mode and source nodes
        do get invalidated when the filter's input is invalidated, such
        as while painting on a layer below the drawable.  This is
        particularly bad for pass-through groups, since their source
        node can be an arbitrarily complex graph, whose invlidation
        incurs a nontrivial overhead.
    
    Instead, don't touch the filter's node at all when visibility
    changes, and rather have GimpFilterStack remove it from the graph
    entirely when the filter becomes invisible, and re-add it once it
    becomes visible again.  This solves both of the above problems, as
    well as simplifies the code.

 app/core/gimpdrawable.c    |  113 +++++++++-------------------
 app/core/gimpfilter.c      |   62 +++------------
 app/core/gimpfilterstack.c |  176 ++++++++++++++++++++++----------------------
 3 files changed, 137 insertions(+), 214 deletions(-)
---
diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c
index 7643362..95c44d7 100644
--- a/app/core/gimpdrawable.c
+++ b/app/core/gimpdrawable.c
@@ -91,7 +91,6 @@ static gboolean   gimp_drawable_get_size           (GimpViewable      *viewable,
                                                     gint              *width,
                                                     gint              *height);
 
-static void       gimp_drawable_visibility_changed (GimpFilter        *filter);
 static GeglNode * gimp_drawable_get_node           (GimpFilter        *filter);
 
 static void       gimp_drawable_removed            (GimpItem          *item);
@@ -226,42 +225,41 @@ gimp_drawable_class_init (GimpDrawableClass *klass)
                   gimp_marshal_VOID__VOID,
                   G_TYPE_NONE, 0);
 
-  object_class->dispose              = gimp_drawable_dispose;
-  object_class->finalize             = gimp_drawable_finalize;
-  object_class->set_property         = gimp_drawable_set_property;
-  object_class->get_property         = gimp_drawable_get_property;
-
-  gimp_object_class->get_memsize     = gimp_drawable_get_memsize;
-
-  viewable_class->get_size           = gimp_drawable_get_size;
-  viewable_class->get_new_preview    = gimp_drawable_get_new_preview;
-  viewable_class->get_new_pixbuf     = gimp_drawable_get_new_pixbuf;
-
-  filter_class->visibility_changed   = gimp_drawable_visibility_changed;
-  filter_class->get_node             = gimp_drawable_get_node;
-
-  item_class->removed                = gimp_drawable_removed;
-  item_class->duplicate              = gimp_drawable_duplicate;
-  item_class->scale                  = gimp_drawable_scale;
-  item_class->resize                 = gimp_drawable_resize;
-  item_class->flip                   = gimp_drawable_flip;
-  item_class->rotate                 = gimp_drawable_rotate;
-  item_class->transform              = gimp_drawable_transform;
-
-  klass->update                      = gimp_drawable_real_update;
-  klass->alpha_changed               = NULL;
-  klass->estimate_memsize            = gimp_drawable_real_estimate_memsize;
-  klass->invalidate_boundary         = NULL;
-  klass->get_active_components       = NULL;
-  klass->get_active_mask             = NULL;
-  klass->convert_type                = gimp_drawable_real_convert_type;
-  klass->apply_buffer                = gimp_drawable_real_apply_buffer;
-  klass->replace_buffer              = gimp_drawable_real_replace_buffer;
-  klass->get_buffer                  = gimp_drawable_real_get_buffer;
-  klass->set_buffer                  = gimp_drawable_real_set_buffer;
-  klass->push_undo                   = gimp_drawable_real_push_undo;
-  klass->swap_pixels                 = gimp_drawable_real_swap_pixels;
-  klass->get_source_node             = gimp_drawable_real_get_source_node;
+  object_class->dispose           = gimp_drawable_dispose;
+  object_class->finalize          = gimp_drawable_finalize;
+  object_class->set_property      = gimp_drawable_set_property;
+  object_class->get_property      = gimp_drawable_get_property;
+
+  gimp_object_class->get_memsize  = gimp_drawable_get_memsize;
+
+  viewable_class->get_size        = gimp_drawable_get_size;
+  viewable_class->get_new_preview = gimp_drawable_get_new_preview;
+  viewable_class->get_new_pixbuf  = gimp_drawable_get_new_pixbuf;
+
+  filter_class->get_node          = gimp_drawable_get_node;
+
+  item_class->removed             = gimp_drawable_removed;
+  item_class->duplicate           = gimp_drawable_duplicate;
+  item_class->scale               = gimp_drawable_scale;
+  item_class->resize              = gimp_drawable_resize;
+  item_class->flip                = gimp_drawable_flip;
+  item_class->rotate              = gimp_drawable_rotate;
+  item_class->transform           = gimp_drawable_transform;
+
+  klass->update                   = gimp_drawable_real_update;
+  klass->alpha_changed            = NULL;
+  klass->estimate_memsize         = gimp_drawable_real_estimate_memsize;
+  klass->invalidate_boundary      = NULL;
+  klass->get_active_components    = NULL;
+  klass->get_active_mask          = NULL;
+  klass->convert_type             = gimp_drawable_real_convert_type;
+  klass->apply_buffer             = gimp_drawable_real_apply_buffer;
+  klass->replace_buffer           = gimp_drawable_real_replace_buffer;
+  klass->get_buffer               = gimp_drawable_real_get_buffer;
+  klass->set_buffer               = gimp_drawable_real_set_buffer;
+  klass->push_undo                = gimp_drawable_real_push_undo;
+  klass->swap_pixels              = gimp_drawable_real_swap_pixels;
+  klass->get_source_node          = gimp_drawable_real_get_source_node;
 
   g_object_class_override_property (object_class, PROP_BUFFER, "buffer");
 
@@ -387,35 +385,6 @@ gimp_drawable_get_size (GimpViewable *viewable,
   return TRUE;
 }
 
-static void
-gimp_drawable_visibility_changed (GimpFilter *filter)
-{
-  GimpDrawable *drawable = GIMP_DRAWABLE (filter);
-  GeglNode     *node;
-
-  /*  don't use gimp_filter_get_node() because that would create
-   *  the node.
-   */
-  node = gimp_filter_peek_node (filter);
-
-  if (node)
-    {
-      GeglNode *output = gegl_node_get_output_proxy (node, "output");
-
-      if (gimp_filter_get_visible (filter))
-        {
-          gegl_node_connect_to (drawable->private->mode_node, "output",
-                                output,                       "input");
-        }
-      else
-        {
-          /* Handled by GimpFilter */
-        }
-    }
-
-  GIMP_FILTER_CLASS (parent_class)->visibility_changed (filter);
-}
-
 static GeglNode *
 gimp_drawable_get_node (GimpFilter *filter)
 {
@@ -438,16 +407,8 @@ gimp_drawable_get_node (GimpFilter *filter)
 
   gegl_node_connect_to (input,                        "output",
                         drawable->private->mode_node, "input");
-
-  if (gimp_filter_get_visible (filter))
-    {
-      gegl_node_connect_to (drawable->private->mode_node, "output",
-                            output,                       "input");
-    }
-  else
-    {
-      /* Handled by GimpFilter */
-    }
+  gegl_node_connect_to (drawable->private->mode_node, "output",
+                        output,                       "input");
 
   return node;
 }
diff --git a/app/core/gimpfilter.c b/app/core/gimpfilter.c
index b2ad85f..951633d 100644
--- a/app/core/gimpfilter.c
+++ b/app/core/gimpfilter.c
@@ -63,21 +63,20 @@ struct _GimpFilterPrivate
 
 /*  local function prototypes  */
 
-static void       gimp_filter_finalize                (GObject      *object);
-static void       gimp_filter_set_property            (GObject      *object,
-                                                       guint         property_id,
-                                                       const GValue *value,
-                                                       GParamSpec   *pspec);
-static void       gimp_filter_get_property            (GObject      *object,
-                                                       guint         property_id,
-                                                       GValue       *value,
-                                                       GParamSpec   *pspec);
+static void       gimp_filter_finalize      (GObject      *object);
+static void       gimp_filter_set_property  (GObject      *object,
+                                             guint         property_id,
+                                             const GValue *value,
+                                             GParamSpec   *pspec);
+static void       gimp_filter_get_property  (GObject      *object,
+                                             guint         property_id,
+                                             GValue       *value,
+                                             GParamSpec   *pspec);
 
-static gint64     gimp_filter_get_memsize             (GimpObject   *object,
-                                                       gint64       *gui_size);
+static gint64     gimp_filter_get_memsize   (GimpObject   *object,
+                                             gint64       *gui_size);
 
-static void       gimp_filter_real_visibility_changed (GimpFilter   *filter);
-static GeglNode * gimp_filter_real_get_node           (GimpFilter   *filter);
+static GeglNode * gimp_filter_real_get_node (GimpFilter   *filter);
 
 
 G_DEFINE_TYPE (GimpFilter, gimp_filter, GIMP_TYPE_VIEWABLE)
@@ -108,7 +107,7 @@ gimp_filter_class_init (GimpFilterClass *klass)
 
   gimp_object_class->get_memsize = gimp_filter_get_memsize;
 
-  klass->visibility_changed      = gimp_filter_real_visibility_changed;
+  klass->visibility_changed      = NULL;
   klass->get_node                = gimp_filter_real_get_node;
 
   g_object_class_install_property (object_class, PROP_VISIBLE,
@@ -202,28 +201,6 @@ gimp_filter_get_memsize (GimpObject *object,
                                                                   gui_size);
 }
 
-static void
-gimp_filter_real_visibility_changed (GimpFilter *filter)
-{
-  GeglNode *node = gimp_filter_peek_node (filter);
-
-  if (node)
-    {
-      if (gimp_filter_get_visible (filter))
-        {
-          /* Leave this up to subclasses */
-        }
-      else
-        {
-          GeglNode *input  = gegl_node_get_input_proxy  (node, "input");
-          GeglNode *output = gegl_node_get_output_proxy (node, "output");
-
-          gegl_node_connect_to (input,  "output",
-                                output, "input");
-        }
-    }
-}
-
 static GeglNode *
 gimp_filter_real_get_node (GimpFilter *filter)
 {
@@ -231,19 +208,6 @@ gimp_filter_real_get_node (GimpFilter *filter)
 
   private->node = gegl_node_new ();
 
-  if (gimp_filter_get_visible (filter))
-    {
-      /* Leave this up to subclasses */
-    }
-  else
-    {
-      GeglNode *input  = gegl_node_get_input_proxy  (private->node, "input");
-      GeglNode *output = gegl_node_get_output_proxy (private->node, "output");
-
-      gegl_node_connect_to (input,  "output",
-                            output, "input");
-    }
-
   return private->node;
 }
 
diff --git a/app/core/gimpfilterstack.c b/app/core/gimpfilterstack.c
index a3cb8a1..18b1e91 100644
--- a/app/core/gimpfilterstack.c
+++ b/app/core/gimpfilterstack.c
@@ -110,13 +110,16 @@ gimp_filter_stack_add (GimpContainer *container,
 
   GIMP_CONTAINER_CLASS (parent_class)->add (container, object);
 
-  if (stack->graph)
+  if (gimp_filter_get_visible (filter))
     {
-      gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
-      gimp_filter_stack_add_node (stack, filter);
-    }
+      if (stack->graph)
+        {
+          gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
+          gimp_filter_stack_add_node (stack, filter);
+        }
 
-  gimp_filter_stack_update_last_node (stack);
+      gimp_filter_stack_update_last_node (stack);
+    }
 }
 
 static void
@@ -126,7 +129,7 @@ gimp_filter_stack_remove (GimpContainer *container,
   GimpFilterStack *stack  = GIMP_FILTER_STACK (container);
   GimpFilter      *filter = GIMP_FILTER (object);
 
-  if (stack->graph)
+  if (stack->graph && gimp_filter_get_visible (filter))
     {
       gimp_filter_stack_remove_node (stack, filter);
       gegl_node_remove_child (stack->graph, gimp_filter_get_node (filter));
@@ -134,8 +137,11 @@ gimp_filter_stack_remove (GimpContainer *container,
 
   GIMP_CONTAINER_CLASS (parent_class)->remove (container, object);
 
-  gimp_filter_set_is_last_node (filter, FALSE);
-  gimp_filter_stack_update_last_node (stack);
+  if (gimp_filter_get_visible (filter))
+    {
+      gimp_filter_set_is_last_node (filter, FALSE);
+      gimp_filter_stack_update_last_node (stack);
+    }
 }
 
 static void
@@ -146,15 +152,18 @@ gimp_filter_stack_reorder (GimpContainer *container,
   GimpFilterStack *stack  = GIMP_FILTER_STACK (container);
   GimpFilter      *filter = GIMP_FILTER (object);
 
-  if (stack->graph)
+  if (stack->graph && gimp_filter_get_visible (filter))
     gimp_filter_stack_remove_node (stack, filter);
 
   GIMP_CONTAINER_CLASS (parent_class)->reorder (container, object, new_index);
 
-  gimp_filter_stack_update_last_node (stack);
+  if (gimp_filter_get_visible (filter))
+    {
+      gimp_filter_stack_update_last_node (stack);
 
-  if (stack->graph)
-    gimp_filter_stack_add_node (stack, filter);
+      if (stack->graph)
+        gimp_filter_stack_add_node (stack, filter);
+    }
 }
 
 
@@ -176,9 +185,7 @@ GeglNode *
 gimp_filter_stack_get_graph (GimpFilterStack *stack)
 {
   GList    *list;
-  GeglNode *first    = NULL;
-  GeglNode *previous = NULL;
-  GeglNode *input;
+  GeglNode *previous;
   GeglNode *output;
 
   g_return_val_if_fail (GIMP_IS_FILTER_STACK (stack), NULL);
@@ -188,40 +195,32 @@ gimp_filter_stack_get_graph (GimpFilterStack *stack)
 
   stack->graph = gegl_node_new ();
 
+  previous = gegl_node_get_input_proxy (stack->graph, "input");
+
   for (list = GIMP_LIST (stack)->queue->tail;
        list;
        list = g_list_previous (list))
     {
       GimpFilter *filter = list->data;
-      GeglNode   *node   = gimp_filter_get_node (filter);
+      GeglNode   *node;
 
-      if (! first)
-        first = node;
+      if (! gimp_filter_get_visible (filter))
+        continue;
+
+      node = gimp_filter_get_node (filter);
 
       gegl_node_add_child (stack->graph, node);
 
-      if (previous)
-        gegl_node_connect_to (previous, "output",
-                              node,     "input");
+      gegl_node_connect_to (previous, "output",
+                            node,     "input");
 
       previous = node;
     }
 
-  input  = gegl_node_get_input_proxy  (stack->graph, "input");
   output = gegl_node_get_output_proxy (stack->graph, "output");
 
-  if (first && previous)
-    {
-      gegl_node_connect_to (input, "output",
-                            first, "input");
-      gegl_node_connect_to (previous, "output",
-                            output,   "input");
-    }
-  else
-    {
-      gegl_node_connect_to (input,  "output",
-                            output, "input");
-    }
+  gegl_node_connect_to (previous, "output",
+                        output,   "input");
 
   return stack->graph;
 }
@@ -233,88 +232,70 @@ static void
 gimp_filter_stack_add_node (GimpFilterStack *stack,
                             GimpFilter      *filter)
 {
-  GimpFilter *filter_below;
-  GeglNode   *node_above;
-  GeglNode   *node_below;
-  GeglNode   *node;
-  gint        index;
+  GeglNode *node;
+  GeglNode *node_above = NULL;
+  GeglNode *node_below = NULL;
+  GList    *iter;
 
   node = gimp_filter_get_node (filter);
 
-  index = gimp_container_get_child_index (GIMP_CONTAINER (stack),
-                                          GIMP_OBJECT (filter));
 
-  if (index == 0)
-    {
-      node_above = gegl_node_get_output_proxy (stack->graph, "output");
-    }
-  else
+  iter = g_list_find (GIMP_LIST (stack)->queue->head, filter);
+
+  while ((iter = g_list_previous (iter)))
     {
-      GimpFilter *filter_above = (GimpFilter *)
-        gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index - 1);
+      GimpFilter *filter_above = iter->data;
 
-      node_above = gimp_filter_get_node (filter_above);
-    }
+      if (gimp_filter_get_visible (filter_above))
+        {
+          node_above = gimp_filter_get_node (filter_above);
 
-  gegl_node_connect_to (node,       "output",
-                        node_above, "input");
+          break;
+        }
+    }
 
-  filter_below = (GimpFilter *)
-    gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index + 1);
+  if (! node_above)
+    node_above = gegl_node_get_output_proxy (stack->graph, "output");
 
-  if (filter_below)
-    {
-      node_below = gimp_filter_get_node (filter_below);
-    }
-  else
-    {
-      node_below = gegl_node_get_input_proxy (stack->graph, "input");
-    }
+  node_below = gegl_node_get_producer (node_above, "input", NULL);
 
   gegl_node_connect_to (node_below, "output",
                         node,       "input");
+  gegl_node_connect_to (node,       "output",
+                        node_above, "input");
 }
 
 static void
 gimp_filter_stack_remove_node (GimpFilterStack *stack,
                                GimpFilter      *filter)
 {
-  GimpFilter *filter_below;
-  GeglNode   *node_above;
-  GeglNode   *node_below;
-  GeglNode   *node;
-  gint        index;
+  GeglNode *node;
+  GeglNode *node_above = NULL;
+  GeglNode *node_below = NULL;
+  GList    *iter;
 
   node = gimp_filter_get_node (filter);
 
-  gegl_node_disconnect (node, "input");
+  iter = g_list_find (GIMP_LIST (stack)->queue->head, filter);
 
-  index = gimp_container_get_child_index (GIMP_CONTAINER (stack),
-                                          GIMP_OBJECT (filter));
-
-  if (index == 0)
-    {
-      node_above = gegl_node_get_output_proxy (stack->graph, "output");
-    }
-  else
+  while ((iter = g_list_previous (iter)))
     {
-      GimpFilter *filter_above = (GimpFilter *)
-        gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index - 1);
+      GimpFilter *filter_above = iter->data;
 
-      node_above = gimp_filter_get_node (filter_above);
+      if (gimp_filter_get_visible (filter_above))
+        {
+          node_above = gimp_filter_get_node (filter_above);
+
+          break;
+        }
     }
 
-  filter_below = (GimpFilter *)
-    gimp_container_get_child_by_index (GIMP_CONTAINER (stack), index + 1);
+  if (! node_above)
+    node_above = gegl_node_get_output_proxy (stack->graph, "output");
 
-  if (filter_below)
-    {
-      node_below = gimp_filter_get_node (filter_below);
-    }
-  else
-    {
-      node_below = gegl_node_get_input_proxy (stack->graph, "input");
-    }
+  node_below = gegl_node_get_producer (node, "input", NULL);
+
+  gegl_node_disconnect (node, "input");
 
   gegl_node_connect_to (node_below, "output",
                         node_above, "input");
@@ -348,5 +329,22 @@ static void
 gimp_filter_stack_filter_visible (GimpFilter      *filter,
                                   GimpFilterStack *stack)
 {
+  if (stack->graph)
+    {
+      if (gimp_filter_get_visible (filter))
+        {
+          gegl_node_add_child (stack->graph, gimp_filter_get_node (filter));
+          gimp_filter_stack_add_node (stack, filter);
+        }
+      else
+        {
+          gimp_filter_stack_remove_node (stack, filter);
+          gegl_node_remove_child (stack->graph, gimp_filter_get_node (filter));
+        }
+    }
+
   gimp_filter_stack_update_last_node (stack);
+
+  if (! gimp_filter_get_visible (filter))
+    gimp_filter_set_is_last_node (filter, FALSE);
 }


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