From 42b262caa98af0029e79d307fed3cfacf09edefa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aur=C3=A9lien=20PIERRE?= <aurelien@aurelienpierre.com>
Date: Tue, 14 Jan 2025 20:25:55 +0100
Subject: [PATCH] Refactor the module operations filtering & fix some "silent"
 bugs

---
 src/develop/develop.c      |  6 ++----
 src/develop/pixelpipe_hb.c | 21 +++++++++++++--------
 src/develop/pixelpipe_hb.h | 11 +++++++++++
 src/iop/ashift.c           |  2 +-
 4 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/src/develop/develop.c b/src/develop/develop.c
index 60f2dcf8435b..266a0429bc28 100644
--- a/src/develop/develop.c
+++ b/src/develop/develop.c
@@ -2360,8 +2360,7 @@ int dt_dev_distort_transform_locked(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe,
            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
-       && !(dev->gui_module && dev->gui_module != module
-            && (dev->gui_module->operation_tags_filter() & module->operation_tags())))
+       && !dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, module))
     {
       module->distort_transform(module, piece, points, points_count);
     }
@@ -2400,8 +2399,7 @@ int dt_dev_distort_backtransform_locked(dt_develop_t *dev, dt_dev_pixelpipe_t *p
            || (transf_direction == DT_DEV_TRANSFORM_DIR_FORW_EXCL && module->iop_order > iop_order)
            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_INCL && module->iop_order <= iop_order)
            || (transf_direction == DT_DEV_TRANSFORM_DIR_BACK_EXCL && module->iop_order < iop_order))
-       && !(dev->gui_module && dev->gui_module != module
-            && (dev->gui_module->operation_tags_filter() & module->operation_tags())))
+       && !dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, module))
     {
       module->distort_backtransform(module, piece, points, points_count);
     }
diff --git a/src/develop/pixelpipe_hb.c b/src/develop/pixelpipe_hb.c
index 97392b2533f9..2a78fd7c4649 100644
--- a/src/develop/pixelpipe_hb.c
+++ b/src/develop/pixelpipe_hb.c
@@ -2389,6 +2389,15 @@ void dt_dev_pixelpipe_flush_caches(dt_dev_pixelpipe_t *pipe)
   dt_dev_pixelpipe_cache_flush(&pipe->cache);
 }
 
+gboolean dt_dev_pixelpipe_activemodule_disables_currentmodule(struct dt_develop_t *dev, struct dt_iop_module_t *current_module)
+{
+  return (dev                 // don't segfault
+          && dev->gui_module  // don't segfault
+          && dev->gui_module != current_module // current_module is not capturing editing mode
+          && dev->gui_module->operation_tags_filter() & current_module->operation_tags());
+          // current_module does operation(s) that active module doesn't want
+}
+
 void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, int width_in,
                                      int height_in, int *width, int *height)
 {
@@ -2405,8 +2414,7 @@ void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, struct dt_develop_t
 
     // skip this module?
     if(piece->enabled
-       && !(dev->gui_module && dev->gui_module != module
-            && dev->gui_module->operation_tags_filter() & module->operation_tags()))
+       && !dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, module))
     {
       module->modify_roi_out(module, piece, &roi_out, &roi_in);
     }
@@ -2448,8 +2456,7 @@ void dt_dev_pixelpipe_get_roi_in(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *
     piece->planned_roi_out = roi_out_temp;
 
     // skip this module?
-    if(piece->enabled && !(dev->gui_module && dev->gui_module != module
-            && dev->gui_module->operation_tags_filter() & module->operation_tags()))
+    if(piece->enabled && !dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, module))
     {
       module->modify_roi_in(module, piece, &roi_out_temp, &roi_in);
 
@@ -2546,8 +2553,7 @@ float *dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *r
           dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
 
           if(module->enabled
-             && !(module->module->dev->gui_module
-                  && (module->module->dev->gui_module->operation_tags_filter() & module->module->operation_tags())))
+             && !dt_dev_pixelpipe_activemodule_disables_currentmodule(module->module->dev, module->module))
           {
             if(module->module->distort_mask
               && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
@@ -2775,8 +2781,7 @@ float *dt_dev_distort_detail_mask(const dt_dev_pixelpipe_t *pipe, float *src, co
     {
       dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
       if(module->enabled
-         && !(module->module->dev->gui_module
-              && module->module->dev->gui_module->operation_tags_filter() & module->module->operation_tags()))
+         && !dt_dev_pixelpipe_activemodule_disables_currentmodule(module->module->dev, module->module))
       {
         if(module->module->distort_mask
               && !(!strcmp(module->module->op, "finalscale") // hack against pipes not using finalscale
diff --git a/src/develop/pixelpipe_hb.h b/src/develop/pixelpipe_hb.h
index 446d96436965..92d77f530f12 100644
--- a/src/develop/pixelpipe_hb.h
+++ b/src/develop/pixelpipe_hb.h
@@ -219,6 +219,17 @@ void dt_dev_pixelpipe_get_roi_out(dt_dev_pixelpipe_t *pipe, struct dt_develop_t
                                      int height_in, int *width, int *height);
 void dt_dev_pixelpipe_get_roi_in(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, const struct dt_iop_roi_t roi_out);
 
+// Check if current_module is performing operations that dev->gui_module (active GUI module)
+// wants disabled. Use that to disable some features of current_module.
+// This is used mostly with distortion operations when the active GUI module
+// needs a full-ROI/undistorted input for its own editing mode,
+// like moving the framing on the full image.
+// WARNING: this doesn't check WHAT particular operations are performed and
+// and what operations should be cancelled (nor if they should all be cancelled).
+// So far, all the code uses that to prevent distortions on module output, masks and roi_out changes (cropping).
+// Meaning ANY of these operations will disable ALL of these operations.
+gboolean dt_dev_pixelpipe_activemodule_disables_currentmodule(struct dt_develop_t *dev,
+                                                              struct dt_iop_module_t *current_module);
 // destroys all allocated data.
 void dt_dev_pixelpipe_cleanup(dt_dev_pixelpipe_t *pipe);
 
diff --git a/src/iop/ashift.c b/src/iop/ashift.c
index 908372c5b378..22724281e86c 100644
--- a/src/iop/ashift.c
+++ b/src/iop/ashift.c
@@ -3657,7 +3657,7 @@ static int call_distort_transform(dt_develop_t *dev, dt_dev_pixelpipe_t *pipe, s
   dt_dev_pixelpipe_iop_t *piece = dt_dev_distort_get_iop_pipe(self->dev, self->dev->preview_pipe, self);
   if(!piece) return ret;
   if(piece->module == self && /*piece->enabled && */  //see note below
-     !(dev->gui_module && dev->gui_module->operation_tags_filter() & piece->module->operation_tags()))
+     !dt_dev_pixelpipe_activemodule_disables_currentmodule(dev, piece->module))
   {
     ret = piece->module->distort_transform(piece->module, piece, points, points_count);
   }