[gimp] app: add gimp_drawable_filter_set_clip()



commit b7f53262fc3df9b5cd0c460afc029a9075e822f0
Author: Ell <ell_se yahoo com>
Date:   Thu Aug 1 23:33:03 2019 +0300

    app: add gimp_drawable_filter_set_clip()
    
    In GimpDrawableFilter, add a new gimp_drawable_filter_set_clip()
    function, which controls whether the filter clips the result to the
    drawable's boundary, or extends it past it.  The latter is only
    possible for layers, when the selection mask is empty.

 app/core/gimpdrawablefilter.c | 191 ++++++++++++++++++++++++++++++++----------
 app/core/gimpdrawablefilter.h |   2 +
 2 files changed, 147 insertions(+), 46 deletions(-)
---
diff --git a/app/core/gimpdrawablefilter.c b/app/core/gimpdrawablefilter.c
index 5c4c1c8527..276f04877f 100644
--- a/app/core/gimpdrawablefilter.c
+++ b/app/core/gimpdrawablefilter.c
@@ -65,6 +65,7 @@ struct _GimpDrawableFilter
 
   gboolean                has_input;
 
+  gboolean                clip;
   GimpFilterRegion        region;
   gboolean                crop_enabled;
   GeglRectangle           crop_rect;
@@ -80,6 +81,7 @@ struct _GimpDrawableFilter
   gboolean                gamma_hack;
 
   GeglRectangle           filter_area;
+  gboolean                filter_clip;
 
   GeglNode               *translate;
   GeglNode               *crop_before;
@@ -93,6 +95,8 @@ struct _GimpDrawableFilter
 static void       gimp_drawable_filter_dispose            (GObject             *object);
 static void       gimp_drawable_filter_finalize           (GObject             *object);
 
+static void       gimp_drawable_filter_sync_clip          (GimpDrawableFilter  *filter,
+                                                           gboolean             sync_region);
 static void       gimp_drawable_filter_sync_region        (GimpDrawableFilter  *filter);
 static void       gimp_drawable_filter_sync_crop          (GimpDrawableFilter  *filter,
                                                            gboolean             old_crop_enabled,
@@ -156,6 +160,7 @@ gimp_drawable_filter_class_init (GimpDrawableFilterClass *klass)
 static void
 gimp_drawable_filter_init (GimpDrawableFilter *drawable_filter)
 {
+  drawable_filter->clip              = TRUE;
   drawable_filter->region            = GIMP_FILTER_REGION_SELECTION;
   drawable_filter->preview_alignment = GIMP_ALIGN_LEFT;
   drawable_filter->preview_position  = 1.0;
@@ -269,6 +274,20 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
   return filter;
 }
 
+void
+gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
+                               gboolean            clip)
+{
+  g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
+
+  if (clip != filter->clip)
+    {
+      filter->clip = clip;
+
+      gimp_drawable_filter_sync_clip (filter, TRUE);
+    }
+}
+
 void
 gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
                                  GimpFilterRegion    region)
@@ -423,6 +442,11 @@ gimp_drawable_filter_apply (GimpDrawableFilter  *filter,
   g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)));
 
   gimp_drawable_filter_add_filter (filter);
+
+  gimp_drawable_filter_sync_clip (filter, TRUE);
+
+  gimp_drawable_update_bounding_box (filter->drawable);
+
   gimp_drawable_filter_update_drawable (filter, area);
 }
 
@@ -448,7 +472,7 @@ gimp_drawable_filter_commit (GimpDrawableFilter *filter,
                                             GIMP_FILTER (filter),
                                             progress,
                                             gimp_object_get_name (filter),
-                                            TRUE,
+                                            filter->filter_clip,
                                             cancellable,
                                             FALSE);
 
@@ -477,6 +501,46 @@ gimp_drawable_filter_abort (GimpDrawableFilter *filter)
 
 /*  private functions  */
 
+static void
+gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
+                                gboolean            sync_region)
+{
+  gboolean clip = filter->clip;
+
+  if (! clip)
+    {
+      if (! GIMP_IS_LAYER (filter->drawable))
+        clip = TRUE;
+    }
+
+  if (! clip)
+    {
+      GimpImage   *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
+      GimpChannel *mask  = gimp_image_get_mask (image);
+
+      if (! gimp_channel_is_empty (mask))
+        clip = TRUE;
+    }
+
+  if (! clip)
+    {
+      GeglRectangle bounding_box;
+
+      bounding_box = gegl_node_get_bounding_box (filter->operation);
+
+      if (gegl_rectangle_is_infinite_plane (&bounding_box))
+        clip = TRUE;
+    }
+
+  if (clip != filter->filter_clip)
+    {
+      filter->filter_clip = clip;
+
+      if (sync_region)
+        gimp_drawable_filter_sync_region (filter);
+    }
+}
+
 static void
 gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
 {
@@ -495,10 +559,22 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
                          NULL);
         }
 
-      gegl_node_set (filter->crop_after,
-                     "width",  (gdouble) filter->filter_area.width,
-                     "height", (gdouble) filter->filter_area.height,
-                     NULL);
+      if (filter->filter_clip)
+        {
+          gegl_node_set (filter->crop_after,
+                         "operation", "gegl:crop",
+                         "x",         0.0,
+                         "y",         0.0,
+                         "width",     (gdouble) filter->filter_area.width,
+                         "height",    (gdouble) filter->filter_area.height,
+                         NULL);
+        }
+      else
+        {
+          gegl_node_set (filter->crop_after,
+                         "operation", "gegl:nop",
+                         NULL);
+        }
 
       gimp_applicator_set_apply_offset (filter->applicator,
                                         filter->filter_area.x,
@@ -523,13 +599,31 @@ gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
                          NULL);
         }
 
-      gegl_node_set (filter->crop_after,
-                     "width",  width,
-                     "height", height,
-                     NULL);
+      if (filter->filter_clip)
+        {
+          gegl_node_set (filter->crop_after,
+                         "operation", "gegl:crop",
+                         "x",         (gdouble) filter->filter_area.x,
+                         "y",         (gdouble) filter->filter_area.y,
+                         "width",     (gdouble) filter->filter_area.width,
+                         "height",    (gdouble) filter->filter_area.height,
+                         NULL);
+        }
+      else
+        {
+          gegl_node_set (filter->crop_after,
+                         "operation", "gegl:nop",
+                         NULL);
+        }
 
       gimp_applicator_set_apply_offset (filter->applicator, 0, 0);
     }
+
+  if (gimp_drawable_filter_is_filtering (filter))
+    {
+      if (gimp_drawable_update_bounding_box (filter->drawable))
+        g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
+    }
 }
 
 static gboolean
@@ -541,37 +635,41 @@ gimp_drawable_filter_get_crop_rect (GimpDrawableFilter  *filter,
                                     gdouble              preview_position,
                                     GeglRectangle       *rect)
 {
-  gint width;
-  gint height;
+  GeglRectangle bounds;
+  gint          width;
+  gint          height;
+  gint          x1, x2;
+  gint          y1, y2;
+
+  bounds = gegl_rectangle_infinite_plane ();
 
-  rect->x      = 0;
-  rect->y      = 0;
-  rect->width  = gimp_item_get_width  (GIMP_ITEM (filter->drawable));
-  rect->height = gimp_item_get_height (GIMP_ITEM (filter->drawable));
+  width  = gimp_item_get_width  (GIMP_ITEM (filter->drawable));
+  height = gimp_item_get_height (GIMP_ITEM (filter->drawable));
 
-  width  = rect->width;
-  height = rect->height;
+  x1 = bounds.x;
+  x2 = bounds.x + bounds.width;
+
+  y1 = bounds.y;
+  y2 = bounds.y + bounds.height;
 
   if (preview_enabled)
     {
       switch (preview_alignment)
         {
         case GIMP_ALIGN_LEFT:
-          rect->width *= preview_position;
+          x2 = width * preview_position;
           break;
 
         case GIMP_ALIGN_RIGHT:
-          rect->width *= (1.0 - preview_position);
-          rect->x = width - rect->width;
+          x1 = width * preview_position;
           break;
 
         case GIMP_ALIGN_TOP:
-          rect->height *= preview_position;
+          y2 = height * preview_position;
           break;
 
         case GIMP_ALIGN_BOTTOM:
-          rect->height *= (1.0 - preview_position);
-          rect->y = height - rect->height;
+          y1 = height * preview_position;
           break;
 
         default:
@@ -579,10 +677,12 @@ gimp_drawable_filter_get_crop_rect (GimpDrawableFilter  *filter,
         }
     }
 
+  gegl_rectangle_set (rect, x1, y1, x2 - x1, y2 - y1);
+
   if (crop_enabled)
     gegl_rectangle_intersect (rect, rect, crop_rect);
 
-  return ! gegl_rectangle_equal_coords (rect, 0, 0, width, height);
+  return ! gegl_rectangle_equal (rect, &bounds);
 }
 
 static void
@@ -616,30 +716,20 @@ gimp_drawable_filter_sync_crop (GimpDrawableFilter  *filter,
 
   gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
 
-  if (update && ! gegl_rectangle_equal (&old_rect, &new_rect))
+  if (update                                     &&
+      gimp_drawable_filter_is_filtering (filter) &&
+      ! gegl_rectangle_equal (&old_rect, &new_rect))
     {
-      cairo_region_t *region;
-      gint            n_rects;
-      gint            i;
+      GeglRectangle diff_rects[4];
+      gint          n_diff_rects;
+      gint          i;
 
-      region = cairo_region_create_rectangle ((cairo_rectangle_int_t *)
-                                              &old_rect);
-      cairo_region_xor_rectangle (region,
-                                  (cairo_rectangle_int_t *) &new_rect);
+      gimp_drawable_update_bounding_box (filter->drawable);
 
-      n_rects = cairo_region_num_rectangles (region);
+      n_diff_rects = gegl_rectangle_xor (diff_rects, &old_rect, &new_rect);
 
-      for (i = 0; i < n_rects; i++)
-        {
-          cairo_rectangle_int_t rect;
-
-          cairo_region_get_rectangle (region, i, &rect);
-
-          gimp_drawable_filter_update_drawable (filter,
-                                                (const GeglRectangle *) &rect);
-        }
-
-      cairo_region_destroy (region);
+      for (i = 0; i < n_diff_rects; i++)
+        gimp_drawable_filter_update_drawable (filter, &diff_rects[i]);
     }
 }
 
@@ -791,6 +881,7 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
       gimp_viewable_preview_freeze (GIMP_VIEWABLE (filter->drawable));
 
       gimp_drawable_filter_sync_mask (filter);
+      gimp_drawable_filter_sync_clip (filter, FALSE);
       gimp_drawable_filter_sync_region (filter);
       gimp_drawable_filter_sync_crop (filter,
                                       filter->crop_enabled,
@@ -808,6 +899,8 @@ gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
       gimp_drawable_add_filter (filter->drawable,
                                 GIMP_FILTER (filter));
 
+      gimp_drawable_update_bounding_box (filter->drawable);
+
       g_signal_connect (image, "component-active-changed",
                         G_CALLBACK (gimp_drawable_filter_affect_changed),
                         filter);
@@ -864,6 +957,8 @@ gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
       gimp_drawable_remove_filter (filter->drawable,
                                    GIMP_FILTER (filter));
 
+      gimp_drawable_update_bounding_box (filter->drawable);
+
       gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
 
       return TRUE;
@@ -876,12 +971,15 @@ static void
 gimp_drawable_filter_update_drawable (GimpDrawableFilter  *filter,
                                       const GeglRectangle *area)
 {
+  GeglRectangle bounding_box;
   GeglRectangle update_area;
 
+  bounding_box = gimp_drawable_get_bounding_box (filter->drawable);
+
   if (area)
     {
       if (! gegl_rectangle_intersect (&update_area,
-                                      area, &filter->filter_area))
+                                      area, &bounding_box))
         {
           return;
         }
@@ -897,7 +995,7 @@ gimp_drawable_filter_update_drawable (GimpDrawableFilter  *filter,
                                           &update_area);
 
       if (! gegl_rectangle_intersect (&update_area,
-                                      &update_area, &filter->filter_area))
+                                      &update_area, &bounding_box))
         {
           return;
         }
@@ -932,6 +1030,7 @@ gimp_drawable_filter_mask_changed (GimpImage          *image,
   gimp_drawable_filter_update_drawable (filter, NULL);
 
   gimp_drawable_filter_sync_mask (filter);
+  gimp_drawable_filter_sync_clip (filter, FALSE);
   gimp_drawable_filter_sync_region (filter);
 
   gimp_drawable_filter_update_drawable (filter, NULL);
diff --git a/app/core/gimpdrawablefilter.h b/app/core/gimpdrawablefilter.h
index 8800190475..53dd214955 100644
--- a/app/core/gimpdrawablefilter.h
+++ b/app/core/gimpdrawablefilter.h
@@ -55,6 +55,8 @@ GimpDrawableFilter *
                                                 GeglNode            *operation,
                                                 const gchar         *icon_name);
 
+void       gimp_drawable_filter_set_clip       (GimpDrawableFilter  *filter,
+                                                gboolean             clip);
 void       gimp_drawable_filter_set_region     (GimpDrawableFilter  *filter,
                                                 GimpFilterRegion     region);
 void       gimp_drawable_filter_set_crop       (GimpDrawableFilter  *filter,


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