1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 /* This file contains the code necessary for generating on canvas
19  * previews, by connecting a specified GEGL operation to do the
20  * processing. It uses drawable filters that allow for non-destructive
21  * manipulation of drawable data, with live preview on screen.
22  *
23  * To create a tool that uses this, see app/tools/gimpfiltertool.c for
24  * the interface and e.g. app/tools/gimpcolorbalancetool.c for an
25  * example of using that interface.
26  */
27 
28 #include "config.h"
29 
30 #include <cairo.h>
31 #include <gdk-pixbuf/gdk-pixbuf.h>
32 #include <gegl.h>
33 
34 #include "libgimpbase/gimpbase.h"
35 #include "libgimpcolor/gimpcolor.h"
36 
37 #include "core-types.h"
38 
39 #include "gegl/gimp-babl.h"
40 #include "gegl/gimpapplicator.h"
41 #include "gegl/gimp-gegl-utils.h"
42 
43 #include "gimpchannel.h"
44 #include "gimpdrawable-filters.h"
45 #include "gimpdrawablefilter.h"
46 #include "gimpimage.h"
47 #include "gimplayer.h"
48 #include "gimpmarshal.h"
49 #include "gimpprogress.h"
50 
51 
52 enum
53 {
54   FLUSH,
55   LAST_SIGNAL
56 };
57 
58 
59 struct _GimpDrawableFilter
60 {
61   GimpFilter              parent_instance;
62 
63   GimpDrawable           *drawable;
64   GeglNode               *operation;
65 
66   gboolean                has_input;
67 
68   gboolean                clip;
69   GimpFilterRegion        region;
70   gboolean                crop_enabled;
71   GeglRectangle           crop_rect;
72   gboolean                preview_enabled;
73   gboolean                preview_split_enabled;
74   GimpAlignmentType       preview_split_alignment;
75   gint                    preview_split_position;
76   gdouble                 opacity;
77   GimpLayerMode           paint_mode;
78   GimpLayerColorSpace     blend_space;
79   GimpLayerColorSpace     composite_space;
80   GimpLayerCompositeMode  composite_mode;
81   gboolean                add_alpha;
82   gboolean                color_managed;
83   gboolean                gamma_hack;
84 
85   gboolean                override_constraints;
86 
87   GeglRectangle           filter_area;
88   gboolean                filter_clip;
89 
90   GeglNode               *translate;
91   GeglNode               *crop_before;
92   GeglNode               *cast_before;
93   GeglNode               *transform_before;
94   GeglNode               *transform_after;
95   GeglNode               *cast_after;
96   GeglNode               *crop_after;
97   GimpApplicator         *applicator;
98 };
99 
100 
101 static void       gimp_drawable_filter_dispose               (GObject             *object);
102 static void       gimp_drawable_filter_finalize              (GObject             *object);
103 
104 static void       gimp_drawable_filter_sync_active           (GimpDrawableFilter  *filter);
105 static void       gimp_drawable_filter_sync_clip             (GimpDrawableFilter  *filter,
106                                                               gboolean             sync_region);
107 static void       gimp_drawable_filter_sync_region           (GimpDrawableFilter  *filter);
108 static void       gimp_drawable_filter_sync_crop             (GimpDrawableFilter  *filter,
109                                                               gboolean             old_crop_enabled,
110                                                               const GeglRectangle *old_crop_rect,
111                                                               gboolean             old_preview_split_enabled,
112                                                               GimpAlignmentType    old_preview_split_alignment,
113                                                               gint                 old_preview_split_position,
114                                                               gboolean             update);
115 static void       gimp_drawable_filter_sync_opacity          (GimpDrawableFilter  *filter);
116 static void       gimp_drawable_filter_sync_mode             (GimpDrawableFilter  *filter);
117 static void       gimp_drawable_filter_sync_affect           (GimpDrawableFilter  *filter);
118 static void       gimp_drawable_filter_sync_format           (GimpDrawableFilter  *filter);
119 static void       gimp_drawable_filter_sync_mask             (GimpDrawableFilter  *filter);
120 static void       gimp_drawable_filter_sync_transform        (GimpDrawableFilter  *filter);
121 static void       gimp_drawable_filter_sync_gamma_hack       (GimpDrawableFilter  *filter);
122 
123 static gboolean   gimp_drawable_filter_is_added              (GimpDrawableFilter  *filter);
124 static gboolean   gimp_drawable_filter_is_active             (GimpDrawableFilter  *filter);
125 static gboolean   gimp_drawable_filter_add_filter            (GimpDrawableFilter  *filter);
126 static gboolean   gimp_drawable_filter_remove_filter         (GimpDrawableFilter  *filter);
127 
128 static void       gimp_drawable_filter_update_drawable       (GimpDrawableFilter  *filter,
129                                                               const GeglRectangle *area);
130 
131 static void       gimp_drawable_filter_affect_changed        (GimpImage           *image,
132                                                               GimpChannelType      channel,
133                                                               GimpDrawableFilter  *filter);
134 static void       gimp_drawable_filter_mask_changed          (GimpImage           *image,
135                                                               GimpDrawableFilter  *filter);
136 static void       gimp_drawable_filter_profile_changed       (GimpColorManaged    *managed,
137                                                               GimpDrawableFilter  *filter);
138 static void       gimp_drawable_filter_lock_position_changed (GimpDrawable        *drawable,
139                                                               GimpDrawableFilter  *filter);
140 static void       gimp_drawable_filter_format_changed        (GimpDrawable        *drawable,
141                                                               GimpDrawableFilter  *filter);
142 static void       gimp_drawable_filter_drawable_removed      (GimpDrawable        *drawable,
143                                                               GimpDrawableFilter  *filter);
144 static void       gimp_drawable_filter_lock_alpha_changed    (GimpLayer           *layer,
145                                                               GimpDrawableFilter  *filter);
146 
147 
148 G_DEFINE_TYPE (GimpDrawableFilter, gimp_drawable_filter, GIMP_TYPE_FILTER)
149 
150 #define parent_class gimp_drawable_filter_parent_class
151 
152 static guint drawable_filter_signals[LAST_SIGNAL] = { 0, };
153 
154 
155 static void
gimp_drawable_filter_class_init(GimpDrawableFilterClass * klass)156 gimp_drawable_filter_class_init (GimpDrawableFilterClass *klass)
157 {
158   GObjectClass *object_class = G_OBJECT_CLASS (klass);
159 
160   drawable_filter_signals[FLUSH] =
161     g_signal_new ("flush",
162                   G_TYPE_FROM_CLASS (klass),
163                   G_SIGNAL_RUN_FIRST,
164                   G_STRUCT_OFFSET (GimpDrawableFilterClass, flush),
165                   NULL, NULL,
166                   gimp_marshal_VOID__VOID,
167                   G_TYPE_NONE, 0);
168 
169   object_class->dispose  = gimp_drawable_filter_dispose;
170   object_class->finalize = gimp_drawable_filter_finalize;
171 }
172 
173 static void
gimp_drawable_filter_init(GimpDrawableFilter * drawable_filter)174 gimp_drawable_filter_init (GimpDrawableFilter *drawable_filter)
175 {
176   drawable_filter->clip                    = TRUE;
177   drawable_filter->region                  = GIMP_FILTER_REGION_SELECTION;
178   drawable_filter->preview_enabled         = TRUE;
179   drawable_filter->preview_split_enabled   = FALSE;
180   drawable_filter->preview_split_alignment = GIMP_ALIGN_LEFT;
181   drawable_filter->preview_split_position  = 0;
182   drawable_filter->opacity                 = GIMP_OPACITY_OPAQUE;
183   drawable_filter->paint_mode              = GIMP_LAYER_MODE_REPLACE;
184   drawable_filter->blend_space             = GIMP_LAYER_COLOR_SPACE_AUTO;
185   drawable_filter->composite_space         = GIMP_LAYER_COLOR_SPACE_AUTO;
186   drawable_filter->composite_mode          = GIMP_LAYER_COMPOSITE_AUTO;
187 }
188 
189 static void
gimp_drawable_filter_dispose(GObject * object)190 gimp_drawable_filter_dispose (GObject *object)
191 {
192   GimpDrawableFilter *drawable_filter = GIMP_DRAWABLE_FILTER (object);
193 
194   if (drawable_filter->drawable)
195     gimp_drawable_filter_remove_filter (drawable_filter);
196 
197   G_OBJECT_CLASS (parent_class)->dispose (object);
198 }
199 
200 static void
gimp_drawable_filter_finalize(GObject * object)201 gimp_drawable_filter_finalize (GObject *object)
202 {
203   GimpDrawableFilter *drawable_filter = GIMP_DRAWABLE_FILTER (object);
204 
205   g_clear_object (&drawable_filter->operation);
206   g_clear_object (&drawable_filter->applicator);
207   g_clear_object (&drawable_filter->drawable);
208 
209   G_OBJECT_CLASS (parent_class)->finalize (object);
210 }
211 
212 GimpDrawableFilter *
gimp_drawable_filter_new(GimpDrawable * drawable,const gchar * undo_desc,GeglNode * operation,const gchar * icon_name)213 gimp_drawable_filter_new (GimpDrawable *drawable,
214                           const gchar  *undo_desc,
215                           GeglNode     *operation,
216                           const gchar  *icon_name)
217 {
218   GimpDrawableFilter *filter;
219   GeglNode           *node;
220 
221   g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
222   g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL);
223   g_return_val_if_fail (GEGL_IS_NODE (operation), NULL);
224   g_return_val_if_fail (gegl_node_has_pad (operation, "output"), NULL);
225 
226   filter = g_object_new (GIMP_TYPE_DRAWABLE_FILTER,
227                          "name",      undo_desc,
228                          "icon-name", icon_name,
229                          NULL);
230 
231   filter->drawable  = g_object_ref (drawable);
232   filter->operation = g_object_ref (operation);
233 
234   node = gimp_filter_get_node (GIMP_FILTER (filter));
235 
236   gegl_node_add_child (node, operation);
237   gimp_gegl_node_set_underlying_operation (node, operation);
238 
239   filter->applicator = gimp_applicator_new (node);
240 
241   gimp_filter_set_applicator (GIMP_FILTER (filter), filter->applicator);
242 
243   gimp_applicator_set_cache (filter->applicator, TRUE);
244 
245   filter->has_input = gegl_node_has_pad (filter->operation, "input");
246 
247   if (filter->has_input)
248     {
249       GeglNode *input;
250 
251       input = gegl_node_get_input_proxy (node, "input");
252 
253       filter->translate = gegl_node_new_child (node,
254                                                "operation", "gegl:translate",
255                                                NULL);
256 
257       filter->crop_before = gegl_node_new_child (node,
258                                                  "operation", "gegl:crop",
259                                                  NULL);
260 
261       filter->cast_before = gegl_node_new_child (node,
262                                                  "operation", "gegl:nop",
263                                                  NULL);
264 
265       filter->transform_before = gegl_node_new_child (node,
266                                                       "operation", "gegl:nop",
267                                                       NULL);
268 
269       gegl_node_link_many (input,
270                            filter->translate,
271                            filter->crop_before,
272                            filter->cast_before,
273                            filter->transform_before,
274                            filter->operation,
275                            NULL);
276     }
277 
278   filter->transform_after = gegl_node_new_child (node,
279                                                  "operation", "gegl:nop",
280                                                  NULL);
281 
282   filter->cast_after = gegl_node_new_child (node,
283                                             "operation", "gegl:nop",
284                                             NULL);
285 
286   filter->crop_after = gegl_node_new_child (node,
287                                             "operation", "gegl:crop",
288                                             NULL);
289 
290   gegl_node_link_many (filter->operation,
291                        filter->transform_after,
292                        filter->cast_after,
293                        filter->crop_after,
294                        NULL);
295 
296   gegl_node_connect_to (filter->crop_after, "output",
297                         node,               "aux");
298 
299   return filter;
300 }
301 
302 GimpDrawable *
gimp_drawable_filter_get_drawable(GimpDrawableFilter * filter)303 gimp_drawable_filter_get_drawable (GimpDrawableFilter *filter)
304 {
305   g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
306 
307   return filter->drawable;
308 }
309 
310 GeglNode *
gimp_drawable_filter_get_operation(GimpDrawableFilter * filter)311 gimp_drawable_filter_get_operation (GimpDrawableFilter *filter)
312 {
313   g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
314 
315   return filter->operation;
316 }
317 
318 void
gimp_drawable_filter_set_clip(GimpDrawableFilter * filter,gboolean clip)319 gimp_drawable_filter_set_clip (GimpDrawableFilter *filter,
320                                gboolean            clip)
321 {
322   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
323 
324   if (clip != filter->clip)
325     {
326       filter->clip = clip;
327 
328       gimp_drawable_filter_sync_clip (filter, TRUE);
329     }
330 }
331 
332 void
gimp_drawable_filter_set_region(GimpDrawableFilter * filter,GimpFilterRegion region)333 gimp_drawable_filter_set_region (GimpDrawableFilter *filter,
334                                  GimpFilterRegion    region)
335 {
336   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
337 
338   if (region != filter->region)
339     {
340       filter->region = region;
341 
342       gimp_drawable_filter_sync_region (filter);
343 
344       if (gimp_drawable_filter_is_active (filter))
345         gimp_drawable_filter_update_drawable (filter, NULL);
346     }
347 }
348 
349 void
gimp_drawable_filter_set_crop(GimpDrawableFilter * filter,const GeglRectangle * rect,gboolean update)350 gimp_drawable_filter_set_crop (GimpDrawableFilter  *filter,
351                                const GeglRectangle *rect,
352                                gboolean             update)
353 {
354   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
355 
356   if ((rect != NULL) != filter->crop_enabled ||
357       (rect && ! gegl_rectangle_equal (rect, &filter->crop_rect)))
358     {
359       gboolean      old_enabled = filter->crop_enabled;
360       GeglRectangle old_rect    = filter->crop_rect;
361 
362       if (rect)
363         {
364           filter->crop_enabled = TRUE;
365           filter->crop_rect    = *rect;
366         }
367       else
368         {
369           filter->crop_enabled = FALSE;
370         }
371 
372       gimp_drawable_filter_sync_crop (filter,
373                                       old_enabled,
374                                       &old_rect,
375                                       filter->preview_split_enabled,
376                                       filter->preview_split_alignment,
377                                       filter->preview_split_position,
378                                       update);
379     }
380 }
381 
382 void
gimp_drawable_filter_set_preview(GimpDrawableFilter * filter,gboolean enabled)383 gimp_drawable_filter_set_preview (GimpDrawableFilter *filter,
384                                   gboolean            enabled)
385 {
386   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
387 
388   if (enabled != filter->preview_enabled)
389     {
390       filter->preview_enabled = enabled;
391 
392       gimp_drawable_filter_sync_active (filter);
393 
394       if (gimp_drawable_filter_is_added (filter))
395         {
396           gimp_drawable_update_bounding_box (filter->drawable);
397 
398           gimp_drawable_filter_update_drawable (filter, NULL);
399         }
400     }
401 }
402 
403 void
gimp_drawable_filter_set_preview_split(GimpDrawableFilter * filter,gboolean enabled,GimpAlignmentType alignment,gint position)404 gimp_drawable_filter_set_preview_split (GimpDrawableFilter  *filter,
405                                         gboolean             enabled,
406                                         GimpAlignmentType    alignment,
407                                         gint                 position)
408 {
409   GimpItem *item;
410 
411   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
412   g_return_if_fail (alignment == GIMP_ALIGN_LEFT  ||
413                     alignment == GIMP_ALIGN_RIGHT ||
414                     alignment == GIMP_ALIGN_TOP   ||
415                     alignment == GIMP_ALIGN_BOTTOM);
416 
417   item = GIMP_ITEM (filter->drawable);
418 
419   switch (alignment)
420     {
421     case GIMP_ALIGN_LEFT:
422     case GIMP_ALIGN_RIGHT:
423       position = CLAMP (position, 0, gimp_item_get_width (item));
424       break;
425 
426     case GIMP_ALIGN_TOP:
427     case GIMP_ALIGN_BOTTOM:
428       position = CLAMP (position, 0, gimp_item_get_height (item));
429       break;
430 
431     default:
432       g_return_if_reached ();
433     }
434 
435   if (enabled   != filter->preview_split_enabled   ||
436       alignment != filter->preview_split_alignment ||
437       position  != filter->preview_split_position)
438     {
439       gboolean          old_enabled   = filter->preview_split_enabled;
440       GimpAlignmentType old_alignment = filter->preview_split_alignment;
441       gint              old_position  = filter->preview_split_position;
442 
443       filter->preview_split_enabled   = enabled;
444       filter->preview_split_alignment = alignment;
445       filter->preview_split_position  = position;
446 
447       gimp_drawable_filter_sync_crop (filter,
448                                       filter->crop_enabled,
449                                       &filter->crop_rect,
450                                       old_enabled,
451                                       old_alignment,
452                                       old_position,
453                                       TRUE);
454     }
455 }
456 
457 void
gimp_drawable_filter_set_opacity(GimpDrawableFilter * filter,gdouble opacity)458 gimp_drawable_filter_set_opacity (GimpDrawableFilter *filter,
459                                   gdouble             opacity)
460 {
461   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
462 
463   if (opacity != filter->opacity)
464     {
465       filter->opacity = opacity;
466 
467       gimp_drawable_filter_sync_opacity (filter);
468 
469       if (gimp_drawable_filter_is_active (filter))
470         gimp_drawable_filter_update_drawable (filter, NULL);
471     }
472 }
473 
474 void
gimp_drawable_filter_set_mode(GimpDrawableFilter * filter,GimpLayerMode paint_mode,GimpLayerColorSpace blend_space,GimpLayerColorSpace composite_space,GimpLayerCompositeMode composite_mode)475 gimp_drawable_filter_set_mode (GimpDrawableFilter     *filter,
476                                GimpLayerMode           paint_mode,
477                                GimpLayerColorSpace     blend_space,
478                                GimpLayerColorSpace     composite_space,
479                                GimpLayerCompositeMode  composite_mode)
480 {
481   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
482 
483   if (paint_mode      != filter->paint_mode      ||
484       blend_space     != filter->blend_space     ||
485       composite_space != filter->composite_space ||
486       composite_mode  != filter->composite_mode)
487     {
488       filter->paint_mode      = paint_mode;
489       filter->blend_space     = blend_space;
490       filter->composite_space = composite_space;
491       filter->composite_mode  = composite_mode;
492 
493       gimp_drawable_filter_sync_mode (filter);
494 
495       if (gimp_drawable_filter_is_active (filter))
496         gimp_drawable_filter_update_drawable (filter, NULL);
497     }
498 }
499 
500 void
gimp_drawable_filter_set_add_alpha(GimpDrawableFilter * filter,gboolean add_alpha)501 gimp_drawable_filter_set_add_alpha (GimpDrawableFilter *filter,
502                                     gboolean            add_alpha)
503 {
504   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
505 
506   if (add_alpha != filter->add_alpha)
507     {
508       filter->add_alpha = add_alpha;
509 
510       gimp_drawable_filter_sync_format (filter);
511 
512       if (gimp_drawable_filter_is_active (filter))
513         gimp_drawable_filter_update_drawable (filter, NULL);
514     }
515 }
516 
517 void
gimp_drawable_filter_set_color_managed(GimpDrawableFilter * filter,gboolean color_managed)518 gimp_drawable_filter_set_color_managed (GimpDrawableFilter *filter,
519                                         gboolean            color_managed)
520 {
521   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
522 
523   if (color_managed != filter->color_managed)
524     {
525       filter->color_managed = color_managed;
526 
527       gimp_drawable_filter_sync_transform (filter);
528 
529       if (gimp_drawable_filter_is_active (filter))
530         gimp_drawable_filter_update_drawable (filter, NULL);
531     }
532 }
533 
534 void
gimp_drawable_filter_set_gamma_hack(GimpDrawableFilter * filter,gboolean gamma_hack)535 gimp_drawable_filter_set_gamma_hack (GimpDrawableFilter *filter,
536                                      gboolean            gamma_hack)
537 {
538   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
539 
540   if (gamma_hack != filter->gamma_hack)
541     {
542       filter->gamma_hack = gamma_hack;
543 
544       gimp_drawable_filter_sync_gamma_hack (filter);
545       gimp_drawable_filter_sync_transform (filter);
546 
547       if (gimp_drawable_filter_is_active (filter))
548         gimp_drawable_filter_update_drawable (filter, NULL);
549     }
550 }
551 
552 void
gimp_drawable_filter_set_override_constraints(GimpDrawableFilter * filter,gboolean override_constraints)553 gimp_drawable_filter_set_override_constraints (GimpDrawableFilter *filter,
554                                                gboolean            override_constraints)
555 {
556   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
557 
558   if (override_constraints != filter->override_constraints)
559     {
560       filter->override_constraints = override_constraints;
561 
562       gimp_drawable_filter_sync_affect (filter);
563       gimp_drawable_filter_sync_format (filter);
564       gimp_drawable_filter_sync_clip   (filter, TRUE);
565 
566       if (gimp_drawable_filter_is_active (filter))
567         gimp_drawable_filter_update_drawable (filter, NULL);
568     }
569 }
570 
571 const Babl *
gimp_drawable_filter_get_format(GimpDrawableFilter * filter)572 gimp_drawable_filter_get_format (GimpDrawableFilter *filter)
573 {
574   const Babl *format;
575 
576   g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), NULL);
577 
578   format = gimp_applicator_get_output_format (filter->applicator);
579 
580   if (! format)
581     format = gimp_drawable_get_format (filter->drawable);
582 
583   return format;
584 }
585 
586 void
gimp_drawable_filter_apply(GimpDrawableFilter * filter,const GeglRectangle * area)587 gimp_drawable_filter_apply (GimpDrawableFilter  *filter,
588                             const GeglRectangle *area)
589 {
590   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
591   g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)));
592 
593   gimp_drawable_filter_add_filter (filter);
594 
595   gimp_drawable_filter_sync_clip (filter, TRUE);
596 
597   if (gimp_drawable_filter_is_active (filter))
598     {
599       gimp_drawable_update_bounding_box (filter->drawable);
600 
601       gimp_drawable_filter_update_drawable (filter, area);
602     }
603 }
604 
605 gboolean
gimp_drawable_filter_commit(GimpDrawableFilter * filter,GimpProgress * progress,gboolean cancellable)606 gimp_drawable_filter_commit (GimpDrawableFilter *filter,
607                              GimpProgress       *progress,
608                              gboolean            cancellable)
609 {
610   gboolean success = TRUE;
611 
612   g_return_val_if_fail (GIMP_IS_DRAWABLE_FILTER (filter), FALSE);
613   g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (filter->drawable)),
614                         FALSE);
615   g_return_val_if_fail (progress == NULL || GIMP_IS_PROGRESS (progress), FALSE);
616 
617   if (gimp_drawable_filter_is_added (filter))
618     {
619       const Babl *format;
620 
621       format = gimp_drawable_filter_get_format (filter);
622 
623       gimp_drawable_filter_set_preview_split (filter, FALSE,
624                                               filter->preview_split_alignment,
625                                               filter->preview_split_position);
626       gimp_drawable_filter_set_preview (filter, TRUE);
627 
628       success = gimp_drawable_merge_filter (filter->drawable,
629                                             GIMP_FILTER (filter),
630                                             progress,
631                                             gimp_object_get_name (filter),
632                                             format,
633                                             filter->filter_clip,
634                                             cancellable,
635                                             FALSE);
636 
637       gimp_drawable_filter_remove_filter (filter);
638 
639       if (! success)
640         gimp_drawable_filter_update_drawable (filter, NULL);
641 
642       g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
643     }
644 
645   return success;
646 }
647 
648 void
gimp_drawable_filter_abort(GimpDrawableFilter * filter)649 gimp_drawable_filter_abort (GimpDrawableFilter *filter)
650 {
651   g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
652 
653   if (gimp_drawable_filter_remove_filter (filter))
654     {
655       gimp_drawable_filter_update_drawable (filter, NULL);
656     }
657 }
658 
659 
660 /*  private functions  */
661 
662 static void
gimp_drawable_filter_sync_active(GimpDrawableFilter * filter)663 gimp_drawable_filter_sync_active (GimpDrawableFilter *filter)
664 {
665   gimp_applicator_set_active (filter->applicator, filter->preview_enabled);
666 }
667 
668 static void
gimp_drawable_filter_sync_clip(GimpDrawableFilter * filter,gboolean sync_region)669 gimp_drawable_filter_sync_clip (GimpDrawableFilter *filter,
670                                 gboolean            sync_region)
671 {
672   gboolean clip;
673 
674   if (filter->override_constraints)
675     clip = filter->clip;
676   else
677     clip = gimp_item_get_clip (GIMP_ITEM (filter->drawable), filter->clip);
678 
679   if (! clip)
680     {
681       GimpImage   *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
682       GimpChannel *mask  = gimp_image_get_mask (image);
683 
684       if (! gimp_channel_is_empty (mask))
685         clip = TRUE;
686     }
687 
688   if (! clip)
689     {
690       GeglRectangle bounding_box;
691 
692       bounding_box = gegl_node_get_bounding_box (filter->operation);
693 
694       if (gegl_rectangle_is_infinite_plane (&bounding_box))
695         clip = TRUE;
696     }
697 
698   if (clip != filter->filter_clip)
699     {
700       filter->filter_clip = clip;
701 
702       if (sync_region)
703         gimp_drawable_filter_sync_region (filter);
704     }
705 }
706 
707 static void
gimp_drawable_filter_sync_region(GimpDrawableFilter * filter)708 gimp_drawable_filter_sync_region (GimpDrawableFilter *filter)
709 {
710   if (filter->region == GIMP_FILTER_REGION_SELECTION)
711     {
712       if (filter->has_input)
713         {
714           gegl_node_set (filter->translate,
715                          "x", (gdouble) -filter->filter_area.x,
716                          "y", (gdouble) -filter->filter_area.y,
717                          NULL);
718 
719           gegl_node_set (filter->crop_before,
720                          "width",  (gdouble) filter->filter_area.width,
721                          "height", (gdouble) filter->filter_area.height,
722                          NULL);
723         }
724 
725       if (filter->filter_clip)
726         {
727           gegl_node_set (filter->crop_after,
728                          "operation", "gegl:crop",
729                          "x",         0.0,
730                          "y",         0.0,
731                          "width",     (gdouble) filter->filter_area.width,
732                          "height",    (gdouble) filter->filter_area.height,
733                          NULL);
734         }
735       else
736         {
737           gegl_node_set (filter->crop_after,
738                          "operation", "gegl:nop",
739                          NULL);
740         }
741 
742       gimp_applicator_set_apply_offset (filter->applicator,
743                                         filter->filter_area.x,
744                                         filter->filter_area.y);
745     }
746   else
747     {
748       GimpItem *item   = GIMP_ITEM (filter->drawable);
749       gdouble   width  = gimp_item_get_width (item);
750       gdouble   height = gimp_item_get_height (item);
751 
752       if (filter->has_input)
753         {
754           gegl_node_set (filter->translate,
755                          "x", (gdouble) 0.0,
756                          "y", (gdouble) 0.0,
757                          NULL);
758 
759           gegl_node_set (filter->crop_before,
760                          "width",  width,
761                          "height", height,
762                          NULL);
763         }
764 
765       if (filter->filter_clip)
766         {
767           gegl_node_set (filter->crop_after,
768                          "operation", "gegl:crop",
769                          "x",         (gdouble) filter->filter_area.x,
770                          "y",         (gdouble) filter->filter_area.y,
771                          "width",     (gdouble) filter->filter_area.width,
772                          "height",    (gdouble) filter->filter_area.height,
773                          NULL);
774         }
775       else
776         {
777           gegl_node_set (filter->crop_after,
778                          "operation", "gegl:nop",
779                          NULL);
780         }
781 
782       gimp_applicator_set_apply_offset (filter->applicator, 0, 0);
783     }
784 
785   if (gimp_drawable_filter_is_active (filter))
786     {
787       if (gimp_drawable_update_bounding_box (filter->drawable))
788         g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
789     }
790 }
791 
792 static gboolean
gimp_drawable_filter_get_crop_rect(GimpDrawableFilter * filter,gboolean crop_enabled,const GeglRectangle * crop_rect,gboolean preview_split_enabled,GimpAlignmentType preview_split_alignment,gint preview_split_position,GeglRectangle * rect)793 gimp_drawable_filter_get_crop_rect (GimpDrawableFilter  *filter,
794                                     gboolean             crop_enabled,
795                                     const GeglRectangle *crop_rect,
796                                     gboolean             preview_split_enabled,
797                                     GimpAlignmentType    preview_split_alignment,
798                                     gint                 preview_split_position,
799                                     GeglRectangle       *rect)
800 {
801   GeglRectangle bounds;
802   gint          x1, x2;
803   gint          y1, y2;
804 
805   bounds = gegl_rectangle_infinite_plane ();
806 
807   x1 = bounds.x;
808   x2 = bounds.x + bounds.width;
809 
810   y1 = bounds.y;
811   y2 = bounds.y + bounds.height;
812 
813   if (preview_split_enabled)
814     {
815       switch (preview_split_alignment)
816         {
817         case GIMP_ALIGN_LEFT:
818           x2 = preview_split_position;
819           break;
820 
821         case GIMP_ALIGN_RIGHT:
822           x1 = preview_split_position;
823           break;
824 
825         case GIMP_ALIGN_TOP:
826           y2 = preview_split_position;
827           break;
828 
829         case GIMP_ALIGN_BOTTOM:
830           y1 = preview_split_position;
831           break;
832 
833         default:
834           g_return_val_if_reached (FALSE);
835         }
836     }
837 
838   gegl_rectangle_set (rect, x1, y1, x2 - x1, y2 - y1);
839 
840   if (crop_enabled)
841     gegl_rectangle_intersect (rect, rect, crop_rect);
842 
843   return ! gegl_rectangle_equal (rect, &bounds);
844 }
845 
846 static void
gimp_drawable_filter_sync_crop(GimpDrawableFilter * filter,gboolean old_crop_enabled,const GeglRectangle * old_crop_rect,gboolean old_preview_split_enabled,GimpAlignmentType old_preview_split_alignment,gint old_preview_split_position,gboolean update)847 gimp_drawable_filter_sync_crop (GimpDrawableFilter  *filter,
848                                 gboolean             old_crop_enabled,
849                                 const GeglRectangle *old_crop_rect,
850                                 gboolean             old_preview_split_enabled,
851                                 GimpAlignmentType    old_preview_split_alignment,
852                                 gint                 old_preview_split_position,
853                                 gboolean             update)
854 {
855   GeglRectangle old_rect;
856   GeglRectangle new_rect;
857   gboolean      enabled;
858 
859   gimp_drawable_filter_get_crop_rect (filter,
860                                       old_crop_enabled,
861                                       old_crop_rect,
862                                       old_preview_split_enabled,
863                                       old_preview_split_alignment,
864                                       old_preview_split_position,
865                                       &old_rect);
866 
867   enabled = gimp_drawable_filter_get_crop_rect (filter,
868                                                 filter->crop_enabled,
869                                                 &filter->crop_rect,
870                                                 filter->preview_split_enabled,
871                                                 filter->preview_split_alignment,
872                                                 filter->preview_split_position,
873                                                 &new_rect);
874 
875   gimp_applicator_set_crop (filter->applicator, enabled ? &new_rect : NULL);
876 
877   if (update                                     &&
878       gimp_drawable_filter_is_active (filter) &&
879       ! gegl_rectangle_equal (&old_rect, &new_rect))
880     {
881       GeglRectangle diff_rects[4];
882       gint          n_diff_rects;
883       gint          i;
884 
885       gimp_drawable_update_bounding_box (filter->drawable);
886 
887       n_diff_rects = gegl_rectangle_xor (diff_rects, &old_rect, &new_rect);
888 
889       for (i = 0; i < n_diff_rects; i++)
890         gimp_drawable_filter_update_drawable (filter, &diff_rects[i]);
891     }
892 }
893 
894 static void
gimp_drawable_filter_sync_opacity(GimpDrawableFilter * filter)895 gimp_drawable_filter_sync_opacity (GimpDrawableFilter *filter)
896 {
897   gimp_applicator_set_opacity (filter->applicator,
898                                filter->opacity);
899 }
900 
901 static void
gimp_drawable_filter_sync_mode(GimpDrawableFilter * filter)902 gimp_drawable_filter_sync_mode (GimpDrawableFilter *filter)
903 {
904   GimpLayerMode paint_mode = filter->paint_mode;
905 
906   if (! filter->has_input && paint_mode == GIMP_LAYER_MODE_REPLACE)
907     {
908       /* if the filter's op has no input, use NORMAL instead of REPLACE, so
909        * that we composite the op's output on top of the input, instead of
910        * completely replacing it.
911        */
912       paint_mode = GIMP_LAYER_MODE_NORMAL;
913     }
914 
915   gimp_applicator_set_mode (filter->applicator,
916                             paint_mode,
917                             filter->blend_space,
918                             filter->composite_space,
919                             filter->composite_mode);
920 }
921 
922 static void
gimp_drawable_filter_sync_affect(GimpDrawableFilter * filter)923 gimp_drawable_filter_sync_affect (GimpDrawableFilter *filter)
924 {
925   gimp_applicator_set_affect (
926     filter->applicator,
927     filter->override_constraints ?
928 
929       GIMP_COMPONENT_MASK_RED   |
930       GIMP_COMPONENT_MASK_GREEN |
931       GIMP_COMPONENT_MASK_BLUE  |
932       GIMP_COMPONENT_MASK_ALPHA :
933 
934       gimp_drawable_get_active_mask (filter->drawable));
935 }
936 
937 static void
gimp_drawable_filter_sync_format(GimpDrawableFilter * filter)938 gimp_drawable_filter_sync_format (GimpDrawableFilter *filter)
939 {
940   const Babl *format;
941 
942   if (filter->add_alpha                                &&
943       (gimp_drawable_supports_alpha (filter->drawable) ||
944        filter->override_constraints))
945     {
946       format = gimp_drawable_get_format_with_alpha (filter->drawable);
947     }
948   else
949     {
950       format = gimp_drawable_get_format (filter->drawable);
951     }
952 
953   gimp_applicator_set_output_format (filter->applicator, format);
954 }
955 
956 static void
gimp_drawable_filter_sync_mask(GimpDrawableFilter * filter)957 gimp_drawable_filter_sync_mask (GimpDrawableFilter *filter)
958 {
959   GimpImage   *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
960   GimpChannel *mask  = gimp_image_get_mask (image);
961 
962   if (gimp_channel_is_empty (mask))
963     {
964       gimp_applicator_set_mask_buffer (filter->applicator, NULL);
965     }
966   else
967     {
968       GeglBuffer *mask_buffer;
969       gint        offset_x, offset_y;
970 
971       mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
972       gimp_item_get_offset (GIMP_ITEM (filter->drawable),
973                             &offset_x, &offset_y);
974 
975       gimp_applicator_set_mask_buffer (filter->applicator, mask_buffer);
976       gimp_applicator_set_mask_offset (filter->applicator,
977                                        -offset_x, -offset_y);
978     }
979 
980   gimp_item_mask_intersect (GIMP_ITEM (filter->drawable),
981                             &filter->filter_area.x,
982                             &filter->filter_area.y,
983                             &filter->filter_area.width,
984                             &filter->filter_area.height);
985 }
986 
987 static void
gimp_drawable_filter_sync_transform(GimpDrawableFilter * filter)988 gimp_drawable_filter_sync_transform (GimpDrawableFilter *filter)
989 {
990   GimpColorManaged *managed = GIMP_COLOR_MANAGED (filter->drawable);
991 
992   if (filter->color_managed)
993     {
994       const Babl       *drawable_format  = NULL;
995       const Babl       *input_format     = NULL;
996       const Babl       *output_format    = NULL;
997       GimpColorProfile *drawable_profile = NULL;
998       GimpColorProfile *input_profile    = NULL;
999       GimpColorProfile *output_profile   = NULL;
1000       guint32           dummy;
1001 
1002       drawable_format = gimp_drawable_get_format (filter->drawable);
1003       if (filter->has_input)
1004         input_format  = gimp_gegl_node_get_format (filter->operation, "input");
1005       output_format   = gimp_gegl_node_get_format (filter->operation, "output");
1006 
1007       g_printerr ("drawable format:      %s\n", babl_get_name (drawable_format));
1008       if (filter->has_input)
1009         g_printerr ("filter input format:  %s\n", babl_get_name (input_format));
1010       g_printerr ("filter output format: %s\n", babl_get_name (output_format));
1011 
1012       /*  convert the drawable format to float, so we get a precise
1013        *  color transform
1014        */
1015       drawable_format =
1016         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
1017                           gimp_babl_precision (GIMP_COMPONENT_TYPE_FLOAT,
1018                                                gimp_babl_format_get_linear (drawable_format)),
1019                           babl_format_has_alpha (drawable_format));
1020 
1021       /*  convert the filter input/output formats to something we have
1022        *  built-in color profiles for (see the get_color_profile()
1023        *  calls below)
1024        */
1025       if (filter->has_input)
1026         input_format = gimp_color_profile_get_lcms_format (input_format,  &dummy);
1027       output_format  = gimp_color_profile_get_lcms_format (output_format, &dummy);
1028 
1029       g_printerr ("profile transform drawable format: %s\n",
1030                   babl_get_name (drawable_format));
1031       if (filter->has_input)
1032         g_printerr ("profile transform input format:    %s\n",
1033                     babl_get_name (input_format));
1034       g_printerr ("profile transform output format:   %s\n",
1035                   babl_get_name (output_format));
1036 
1037       drawable_profile = gimp_color_managed_get_color_profile (managed);
1038       if (filter->has_input)
1039         input_profile  = gimp_babl_format_get_color_profile (input_format);
1040       output_profile   = gimp_babl_format_get_color_profile (output_format);
1041 
1042       if ((filter->has_input &&
1043            ! gimp_color_transform_can_gegl_copy (drawable_profile,
1044                                                  input_profile)) ||
1045           ! gimp_color_transform_can_gegl_copy (output_profile,
1046                                                 drawable_profile))
1047         {
1048           g_printerr ("using gimp:profile-transform\n");
1049 
1050           if (filter->has_input)
1051             {
1052               gegl_node_set (filter->transform_before,
1053                              "operation",    "gimp:profile-transform",
1054                              "src-profile",  drawable_profile,
1055                              "src-format",   drawable_format,
1056                              "dest-profile", input_profile,
1057                              "dest-format",  input_format,
1058                              NULL);
1059             }
1060 
1061           gegl_node_set (filter->transform_after,
1062                          "operation",    "gimp:profile-transform",
1063                          "src-profile",  output_profile,
1064                          "src-format",   output_format,
1065                          "dest-profile", drawable_profile,
1066                          "dest-format",  drawable_format,
1067                          NULL);
1068 
1069           return;
1070         }
1071     }
1072 
1073   g_printerr ("using gegl copy\n");
1074 
1075   if (filter->has_input)
1076     {
1077       gegl_node_set (filter->transform_before,
1078                      "operation", "gegl:nop",
1079                      NULL);
1080     }
1081 
1082   gegl_node_set (filter->transform_after,
1083                  "operation", "gegl:nop",
1084                  NULL);
1085 }
1086 
1087 static void
gimp_drawable_filter_sync_gamma_hack(GimpDrawableFilter * filter)1088 gimp_drawable_filter_sync_gamma_hack (GimpDrawableFilter *filter)
1089 {
1090   if (filter->gamma_hack)
1091     {
1092       const Babl *drawable_format;
1093       const Babl *cast_format;
1094 
1095       drawable_format =
1096         gimp_drawable_get_format_with_alpha (filter->drawable);
1097 
1098       cast_format =
1099         gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
1100                           gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
1101                                                ! gimp_babl_format_get_linear (drawable_format)),
1102                           TRUE);
1103 
1104       if (filter->has_input)
1105         {
1106           gegl_node_set (filter->cast_before,
1107                          "operation",     "gegl:cast-format",
1108                          "input-format",  drawable_format,
1109                          "output-format", cast_format,
1110                          NULL);
1111         }
1112 
1113       gegl_node_set (filter->cast_after,
1114                      "operation",     "gegl:cast-format",
1115                      "input-format",  cast_format,
1116                      "output-format", drawable_format,
1117                      NULL);
1118     }
1119   else
1120     {
1121       if (filter->has_input)
1122         {
1123           gegl_node_set (filter->cast_before,
1124                          "operation", "gegl:nop",
1125                          NULL);
1126         }
1127 
1128       gegl_node_set (filter->cast_after,
1129                      "operation", "gegl:nop",
1130                      NULL);
1131     }
1132 }
1133 
1134 static gboolean
gimp_drawable_filter_is_added(GimpDrawableFilter * filter)1135 gimp_drawable_filter_is_added (GimpDrawableFilter *filter)
1136 {
1137   return gimp_drawable_has_filter (filter->drawable,
1138                                    GIMP_FILTER (filter));
1139 }
1140 
1141 static gboolean
gimp_drawable_filter_is_active(GimpDrawableFilter * filter)1142 gimp_drawable_filter_is_active (GimpDrawableFilter *filter)
1143 {
1144   return gimp_drawable_filter_is_added (filter) &&
1145          filter->preview_enabled;
1146 }
1147 
1148 static gboolean
gimp_drawable_filter_add_filter(GimpDrawableFilter * filter)1149 gimp_drawable_filter_add_filter (GimpDrawableFilter *filter)
1150 {
1151   if (! gimp_drawable_filter_is_added (filter))
1152     {
1153       GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
1154 
1155       gimp_viewable_preview_freeze (GIMP_VIEWABLE (filter->drawable));
1156 
1157       gimp_drawable_filter_sync_active (filter);
1158       gimp_drawable_filter_sync_mask (filter);
1159       gimp_drawable_filter_sync_clip (filter, FALSE);
1160       gimp_drawable_filter_sync_region (filter);
1161       gimp_drawable_filter_sync_crop (filter,
1162                                       filter->crop_enabled,
1163                                       &filter->crop_rect,
1164                                       filter->preview_split_enabled,
1165                                       filter->preview_split_alignment,
1166                                       filter->preview_split_position,
1167                                       TRUE);
1168       gimp_drawable_filter_sync_opacity (filter);
1169       gimp_drawable_filter_sync_mode (filter);
1170       gimp_drawable_filter_sync_affect (filter);
1171       gimp_drawable_filter_sync_format (filter);
1172       gimp_drawable_filter_sync_transform (filter);
1173       gimp_drawable_filter_sync_gamma_hack (filter);
1174 
1175       gimp_drawable_add_filter (filter->drawable,
1176                                 GIMP_FILTER (filter));
1177 
1178       gimp_drawable_update_bounding_box (filter->drawable);
1179 
1180       g_signal_connect (image, "component-active-changed",
1181                         G_CALLBACK (gimp_drawable_filter_affect_changed),
1182                         filter);
1183       g_signal_connect (image, "mask-changed",
1184                         G_CALLBACK (gimp_drawable_filter_mask_changed),
1185                         filter);
1186       g_signal_connect (image, "profile-changed",
1187                         G_CALLBACK (gimp_drawable_filter_profile_changed),
1188                         filter);
1189       g_signal_connect (filter->drawable, "lock-position-changed",
1190                         G_CALLBACK (gimp_drawable_filter_lock_position_changed),
1191                         filter);
1192       g_signal_connect (filter->drawable, "format-changed",
1193                         G_CALLBACK (gimp_drawable_filter_format_changed),
1194                         filter);
1195       g_signal_connect (filter->drawable, "removed",
1196                         G_CALLBACK (gimp_drawable_filter_drawable_removed),
1197                         filter);
1198 
1199       if (GIMP_IS_LAYER (filter->drawable))
1200         {
1201           g_signal_connect (filter->drawable, "lock-alpha-changed",
1202                             G_CALLBACK (gimp_drawable_filter_lock_alpha_changed),
1203                             filter);
1204         }
1205 
1206       return TRUE;
1207     }
1208 
1209   return FALSE;
1210 }
1211 
1212 static gboolean
gimp_drawable_filter_remove_filter(GimpDrawableFilter * filter)1213 gimp_drawable_filter_remove_filter (GimpDrawableFilter *filter)
1214 {
1215   if (gimp_drawable_filter_is_added (filter))
1216     {
1217       GimpImage *image = gimp_item_get_image (GIMP_ITEM (filter->drawable));
1218 
1219       if (GIMP_IS_LAYER (filter->drawable))
1220         {
1221           g_signal_handlers_disconnect_by_func (filter->drawable,
1222                                                 gimp_drawable_filter_lock_alpha_changed,
1223                                                 filter);
1224         }
1225 
1226       g_signal_handlers_disconnect_by_func (filter->drawable,
1227                                             gimp_drawable_filter_drawable_removed,
1228                                             filter);
1229       g_signal_handlers_disconnect_by_func (filter->drawable,
1230                                             gimp_drawable_filter_format_changed,
1231                                             filter);
1232       g_signal_handlers_disconnect_by_func (filter->drawable,
1233                                             gimp_drawable_filter_lock_position_changed,
1234                                             filter);
1235       g_signal_handlers_disconnect_by_func (image,
1236                                             gimp_drawable_filter_profile_changed,
1237                                             filter);
1238       g_signal_handlers_disconnect_by_func (image,
1239                                             gimp_drawable_filter_mask_changed,
1240                                             filter);
1241       g_signal_handlers_disconnect_by_func (image,
1242                                             gimp_drawable_filter_affect_changed,
1243                                             filter);
1244 
1245       gimp_drawable_remove_filter (filter->drawable,
1246                                    GIMP_FILTER (filter));
1247 
1248       gimp_drawable_update_bounding_box (filter->drawable);
1249 
1250       gimp_viewable_preview_thaw (GIMP_VIEWABLE (filter->drawable));
1251 
1252       return TRUE;
1253     }
1254 
1255   return FALSE;
1256 }
1257 
1258 static void
gimp_drawable_filter_update_drawable(GimpDrawableFilter * filter,const GeglRectangle * area)1259 gimp_drawable_filter_update_drawable (GimpDrawableFilter  *filter,
1260                                       const GeglRectangle *area)
1261 {
1262   GeglRectangle bounding_box;
1263   GeglRectangle update_area;
1264 
1265   bounding_box = gimp_drawable_get_bounding_box (filter->drawable);
1266 
1267   if (area)
1268     {
1269       if (! gegl_rectangle_intersect (&update_area,
1270                                       area, &bounding_box))
1271         {
1272           return;
1273         }
1274     }
1275   else
1276     {
1277       gimp_drawable_filter_get_crop_rect (filter,
1278                                           filter->crop_enabled,
1279                                           &filter->crop_rect,
1280                                           filter->preview_split_enabled,
1281                                           filter->preview_split_alignment,
1282                                           filter->preview_split_position,
1283                                           &update_area);
1284 
1285       if (! gegl_rectangle_intersect (&update_area,
1286                                       &update_area, &bounding_box))
1287         {
1288           return;
1289         }
1290     }
1291 
1292   if (update_area.width  > 0 &&
1293       update_area.height > 0)
1294     {
1295       gimp_drawable_update (filter->drawable,
1296                             update_area.x,
1297                             update_area.y,
1298                             update_area.width,
1299                             update_area.height);
1300 
1301       g_signal_emit (filter, drawable_filter_signals[FLUSH], 0);
1302     }
1303 }
1304 
1305 static void
gimp_drawable_filter_affect_changed(GimpImage * image,GimpChannelType channel,GimpDrawableFilter * filter)1306 gimp_drawable_filter_affect_changed (GimpImage          *image,
1307                                      GimpChannelType     channel,
1308                                      GimpDrawableFilter *filter)
1309 {
1310   gimp_drawable_filter_sync_affect (filter);
1311   gimp_drawable_filter_update_drawable (filter, NULL);
1312 }
1313 
1314 static void
gimp_drawable_filter_mask_changed(GimpImage * image,GimpDrawableFilter * filter)1315 gimp_drawable_filter_mask_changed (GimpImage          *image,
1316                                    GimpDrawableFilter *filter)
1317 {
1318   gimp_drawable_filter_update_drawable (filter, NULL);
1319 
1320   gimp_drawable_filter_sync_mask (filter);
1321   gimp_drawable_filter_sync_clip (filter, FALSE);
1322   gimp_drawable_filter_sync_region (filter);
1323 
1324   gimp_drawable_filter_update_drawable (filter, NULL);
1325 }
1326 
1327 static void
gimp_drawable_filter_profile_changed(GimpColorManaged * managed,GimpDrawableFilter * filter)1328 gimp_drawable_filter_profile_changed (GimpColorManaged   *managed,
1329                                       GimpDrawableFilter *filter)
1330 {
1331   gimp_drawable_filter_sync_transform (filter);
1332   gimp_drawable_filter_update_drawable (filter, NULL);
1333 }
1334 
1335 static void
gimp_drawable_filter_lock_position_changed(GimpDrawable * drawable,GimpDrawableFilter * filter)1336 gimp_drawable_filter_lock_position_changed (GimpDrawable       *drawable,
1337                                             GimpDrawableFilter *filter)
1338 {
1339   gimp_drawable_filter_sync_clip (filter, TRUE);
1340   gimp_drawable_filter_update_drawable (filter, NULL);
1341 }
1342 
1343 static void
gimp_drawable_filter_format_changed(GimpDrawable * drawable,GimpDrawableFilter * filter)1344 gimp_drawable_filter_format_changed (GimpDrawable       *drawable,
1345                                      GimpDrawableFilter *filter)
1346 {
1347   gimp_drawable_filter_sync_format (filter);
1348   gimp_drawable_filter_update_drawable (filter, NULL);
1349 }
1350 
1351 static void
gimp_drawable_filter_drawable_removed(GimpDrawable * drawable,GimpDrawableFilter * filter)1352 gimp_drawable_filter_drawable_removed (GimpDrawable       *drawable,
1353                                        GimpDrawableFilter *filter)
1354 {
1355   gimp_drawable_filter_remove_filter (filter);
1356 }
1357 
1358 static void
gimp_drawable_filter_lock_alpha_changed(GimpLayer * layer,GimpDrawableFilter * filter)1359 gimp_drawable_filter_lock_alpha_changed (GimpLayer          *layer,
1360                                          GimpDrawableFilter *filter)
1361 {
1362   gimp_drawable_filter_sync_affect (filter);
1363   gimp_drawable_filter_update_drawable (filter, NULL);
1364 }
1365