From 4c15be6a566247d5743341ada68badaffc1a6a95 Mon Sep 17 00:00:00 2001 From: Jehan Date: Sat, 28 Feb 2026 20:01:28 +0100 Subject: [PATCH] app: fix merging filters with negative top-left point. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When merging filters whose rendering was expanding in negative ccordinates, I realized that the drawable was not properly resized (it was resized properly when the width/height increased, but not when the x or y points became negative, even though this "cropped" part still showed… until you saved and reloaded your XCF!). The problem is that drawable buffers are always stored with (0, 0) top-left and this was just confusing our existing code. So let's check when trying to set a buffer with a non-(0, 0) origin, and update the offset subsequently. I hesitated with an alternative implementation which was to edit the buffer applied to the drawable in gimp_drawable_merge_filters(). But I figured this would be more future-proof for other similar cases, though I hope I did not break any use case where this was actually considered a normal case. --- app/core/gimpdrawable.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 646c960af9..92d3da3577 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -1013,9 +1013,11 @@ gimp_drawable_real_set_buffer (GimpDrawable *drawable, GeglBuffer *buffer, const GeglRectangle *bounds) { - GimpItem *item = GIMP_ITEM (drawable); - const Babl *old_format = NULL; - gint old_has_alpha = -1; + GimpItem *item = GIMP_ITEM (drawable); + const Babl *old_format = NULL; + gint old_has_alpha = -1; + const GeglRectangle *extent = gegl_buffer_get_extent (buffer); + gboolean free_buffer = FALSE; g_object_freeze_notify (G_OBJECT (drawable)); @@ -1031,6 +1033,22 @@ gimp_drawable_real_set_buffer (GimpDrawable *drawable, old_has_alpha = gimp_drawable_has_alpha (drawable); } + if (extent->x != 0 || extent->y != 0) + { + /* Drawable buffers are always stored with a (0, 0) origin. When + * setting a buffer with a different origin, we will assume we + * instead want to update the offset a bit. + * This may happen for instance when merging filters which may + * render in negative coordinates. + */ + buffer = g_object_new (GEGL_TYPE_BUFFER, + "source", buffer, + "shift-x", extent->x, + "shift-y", extent->y, + NULL); + free_buffer = TRUE; + } + g_set_object (&drawable->private->buffer, buffer); if (gimp_drawable_is_painting (drawable)) @@ -1043,7 +1061,7 @@ gimp_drawable_real_set_buffer (GimpDrawable *drawable, "buffer", gimp_drawable_get_buffer (drawable), NULL); - gimp_item_set_offset (item, bounds->x, bounds->y); + gimp_item_set_offset (item, bounds->x + extent->x, bounds->y + extent->y); gimp_item_set_size (item, bounds->width ? bounds->width : gegl_buffer_get_width (buffer), @@ -1061,6 +1079,9 @@ gimp_drawable_real_set_buffer (GimpDrawable *drawable, g_object_notify (G_OBJECT (drawable), "buffer"); g_object_thaw_notify (G_OBJECT (drawable)); + + if (free_buffer) + g_object_unref (buffer); } static GeglRectangle