app: fix merging filters with negative top-left point.

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.
This commit is contained in:
Jehan 2026-02-28 20:01:28 +01:00
parent 018eafc146
commit 4c15be6a56

View file

@ -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