[gimp] app: add support for projectables with an arbitrary bounding box
- From: Ell <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: add support for projectables with an arbitrary bounding box
- Date: Thu, 1 Aug 2019 21:42:05 +0000 (UTC)
commit 8ff43942d6ea6dc7ef34200249e28861de0573e0
Author: Ell <ell_se yahoo com>
Date: Thu Aug 1 23:01:58 2019 +0300
app: add support for projectables with an arbitrary bounding box
In GimpProjectable, replace gimp_projectable_get_size(), which only
returned a width and a height, with
gimp_projectable_get_bounding_box(), which returns a full
rectangle. This allows projectables to have an arbitrary bounding
box, not limited to a (0, 0) top-left corner.
Adapt GimpProjection, creating a buffer with corresponding extent
to the projectable's bounding box.
Adapt GimpImage and GimpGroupLayer.
app/core/gimpgrouplayer.c | 53 ++++++++------
app/core/gimpimage.c | 13 +++-
app/core/gimpprojectable.c | 30 +++-----
app/core/gimpprojectable.h | 16 ++---
app/core/gimpprojection.c | 173 ++++++++++++++++++++++++++++-----------------
5 files changed, 170 insertions(+), 115 deletions(-)
---
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index 249b661b1c..2ee54c77a0 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -179,6 +179,8 @@ static gboolean
gimp_group_layer_get_excludes_backdrop (GimpLayer *layer);
static const Babl * gimp_group_layer_get_format (GimpProjectable *projectable);
+static GeglRectangle
+ gimp_group_layer_get_bounding_box (GimpProjectable *projectable);
static GeglNode * gimp_group_layer_get_graph (GimpProjectable *projectable);
static void gimp_group_layer_begin_render (GimpProjectable *projectable);
static void gimp_group_layer_end_render (GimpProjectable *projectable);
@@ -313,7 +315,7 @@ gimp_projectable_iface_init (GimpProjectableInterface *iface)
iface->get_image = (GimpImage * (*) (GimpProjectable *)) gimp_item_get_image;
iface->get_format = gimp_group_layer_get_format;
iface->get_offset = (void (*) (GimpProjectable*, gint*, gint*)) gimp_item_get_offset;
- iface->get_size = (void (*) (GimpProjectable*, gint*, gint*)) gimp_viewable_get_size;
+ iface->get_bounding_box = gimp_group_layer_get_bounding_box;
iface->get_graph = gimp_group_layer_get_graph;
iface->begin_render = gimp_group_layer_begin_render;
iface->end_render = gimp_group_layer_end_render;
@@ -458,29 +460,16 @@ gimp_group_layer_get_size (GimpViewable *viewable,
gint *height)
{
GimpGroupLayerPrivate *private = GET_PRIVATE (viewable);
- gboolean result;
- if (private->reallocate_width != 0 &&
- private->reallocate_height != 0)
+ /* return the size only if there are children ... */
+ if (! gimp_container_is_empty (private->children))
{
- *width = private->reallocate_width;
- *height = private->reallocate_height;
-
- return TRUE;
+ return GIMP_VIEWABLE_CLASS (parent_class)->get_size (viewable,
+ width, height);
}
- result = GIMP_VIEWABLE_CLASS (parent_class)->get_size (viewable,
- width, height);
-
- /* if the group is empty, return "no content" through
- * gimp_viewable_get_size(), but make sure to set *width and *height anyway,
- * so that the correct size is reported to the projection through
- * gimp_projectable_get_size(). see issue #3134.
- */
- if (gimp_container_is_empty (private->children))
- result = FALSE;
-
- return result;
+ /* ... otherwise, return "no content" */
+ return FALSE;
}
static GimpContainer *
@@ -1345,6 +1334,30 @@ gimp_group_layer_get_format (GimpProjectable *projectable)
return get_projection_format (projectable, base_type, precision);
}
+static GeglRectangle
+gimp_group_layer_get_bounding_box (GimpProjectable *projectable)
+{
+ GimpGroupLayerPrivate *private = GET_PRIVATE (projectable);
+ GeglRectangle bounding_box;
+
+ bounding_box.x = 0;
+ bounding_box.y = 0;
+
+ if (private->reallocate_width != 0 &&
+ private->reallocate_height != 0)
+ {
+ bounding_box.width = private->reallocate_width;
+ bounding_box.height = private->reallocate_height;
+ }
+ else
+ {
+ bounding_box.width = gimp_item_get_width (GIMP_ITEM (projectable));
+ bounding_box.height = gimp_item_get_height (GIMP_ITEM (projectable));
+ }
+
+ return bounding_box;
+}
+
static GeglNode *
gimp_group_layer_get_graph (GimpProjectable *projectable)
{
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index e3dfb7435d..37875b6bfd 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -194,6 +194,7 @@ static void
static void gimp_image_projectable_flush (GimpProjectable *projectable,
gboolean invalidate_preview);
+static GeglRectangle gimp_image_get_bounding_box (GimpProjectable *projectable);
static GeglNode * gimp_image_get_graph (GimpProjectable *projectable);
static GimpImage * gimp_image_get_image (GimpProjectable *projectable);
static const Babl * gimp_image_get_proj_format (GimpProjectable *projectable);
@@ -678,7 +679,7 @@ gimp_projectable_iface_init (GimpProjectableInterface *iface)
iface->flush = gimp_image_projectable_flush;
iface->get_image = gimp_image_get_image;
iface->get_format = gimp_image_get_proj_format;
- iface->get_size = (void (*) (GimpProjectable*, gint*, gint*)) gimp_image_get_size;
+ iface->get_bounding_box = gimp_image_get_bounding_box;
iface->get_graph = gimp_image_get_graph;
iface->invalidate_preview = (void (*) (GimpProjectable*)) gimp_viewable_invalidate_preview;
}
@@ -1479,6 +1480,16 @@ gimp_image_srgb_to_pixel (GimpPickable *pickable,
color, format, pixel);
}
+static GeglRectangle
+gimp_image_get_bounding_box (GimpProjectable *projectable)
+{
+ GimpImage *image = GIMP_IMAGE (projectable);
+
+ return *GEGL_RECTANGLE (0, 0,
+ gimp_image_get_width (image),
+ gimp_image_get_height (image));
+}
+
static GeglNode *
gimp_image_get_graph (GimpProjectable *projectable)
{
diff --git a/app/core/gimpprojectable.c b/app/core/gimpprojectable.c
index e8ded97492..8814c98eb9 100644
--- a/app/core/gimpprojectable.c
+++ b/app/core/gimpprojectable.c
@@ -90,10 +90,8 @@ gimp_projectable_default_init (GimpProjectableInterface *iface)
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GimpProjectableInterface, bounds_changed),
NULL, NULL,
- gimp_marshal_VOID__INT_INT_INT_INT,
- G_TYPE_NONE, 4,
- G_TYPE_INT,
- G_TYPE_INT,
+ gimp_marshal_VOID__INT_INT,
+ G_TYPE_NONE, 2,
G_TYPE_INT,
G_TYPE_INT);
}
@@ -135,14 +133,12 @@ gimp_projectable_structure_changed (GimpProjectable *projectable)
void
gimp_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
- gint old_y,
- gint old_width,
- gint old_height)
+ gint old_y)
{
g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
g_signal_emit (projectable, projectable_signals[BOUNDS_CHANGED], 0,
- old_x, old_y, old_width, old_height);
+ old_x, old_y);
}
GimpImage *
@@ -195,24 +191,20 @@ gimp_projectable_get_offset (GimpProjectable *projectable,
iface->get_offset (projectable, x, y);
}
-void
-gimp_projectable_get_size (GimpProjectable *projectable,
- gint *width,
- gint *height)
+GeglRectangle
+gimp_projectable_get_bounding_box (GimpProjectable *projectable)
{
GimpProjectableInterface *iface;
+ GeglRectangle result = {};
- g_return_if_fail (GIMP_IS_PROJECTABLE (projectable));
- g_return_if_fail (width != NULL);
- g_return_if_fail (height != NULL);
+ g_return_val_if_fail (GIMP_IS_PROJECTABLE (projectable), result);
iface = GIMP_PROJECTABLE_GET_INTERFACE (projectable);
- *width = 0;
- *height = 0;
+ if (iface->get_bounding_box)
+ result = iface->get_bounding_box (projectable);
- if (iface->get_size)
- iface->get_size (projectable, width, height);
+ return result;
}
GeglNode *
diff --git a/app/core/gimpprojectable.h b/app/core/gimpprojectable.h
index 836017dabd..955f3a4cb8 100644
--- a/app/core/gimpprojectable.h
+++ b/app/core/gimpprojectable.h
@@ -45,9 +45,7 @@ struct _GimpProjectableInterface
void (* structure_changed) (GimpProjectable *projectable);
void (* bounds_changed) (GimpProjectable *projectable,
gint old_x,
- gint old_y,
- gint old_width,
- gint old_height);
+ gint old_y);
/* virtual functions */
GimpImage * (* get_image) (GimpProjectable *projectable);
@@ -55,9 +53,7 @@ struct _GimpProjectableInterface
void (* get_offset) (GimpProjectable *projectable,
gint *x,
gint *y);
- void (* get_size) (GimpProjectable *projectable,
- gint *width,
- gint *height);
+ GeglRectangle (* get_bounding_box) (GimpProjectable *projectable);
GeglNode * (* get_graph) (GimpProjectable *projectable);
void (* begin_render) (GimpProjectable *projectable);
void (* end_render) (GimpProjectable *projectable);
@@ -77,18 +73,14 @@ void gimp_projectable_flush (GimpProjectable *projectable,
void gimp_projectable_structure_changed (GimpProjectable *projectable);
void gimp_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
- gint old_y,
- gint old_width,
- gint old_height);
+ gint old_y);
GimpImage * gimp_projectable_get_image (GimpProjectable *projectable);
const Babl * gimp_projectable_get_format (GimpProjectable *projectable);
void gimp_projectable_get_offset (GimpProjectable *projectable,
gint *x,
gint *y);
-void gimp_projectable_get_size (GimpProjectable *projectable,
- gint *width,
- gint *height);
+GeglRectangle gimp_projectable_get_bounding_box (GimpProjectable *projectable);
GeglNode * gimp_projectable_get_graph (GimpProjectable *projectable);
void gimp_projectable_begin_render (GimpProjectable *projectable);
void gimp_projectable_end_render (GimpProjectable *projectable);
diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c
index f74321210c..697414adf3 100644
--- a/app/core/gimpprojection.c
+++ b/app/core/gimpprojection.c
@@ -163,8 +163,6 @@ static void
static void gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
gint old_y,
- gint old_w,
- gint old_h,
GimpProjection *proj);
@@ -365,10 +363,10 @@ gimp_projection_get_buffer (GimpPickable *pickable)
if (! proj->priv->buffer)
{
- gint width;
- gint height;
+ GeglRectangle bounding_box;
- gimp_projectable_get_size (proj->priv->projectable, &width, &height);
+ bounding_box =
+ gimp_projectable_get_bounding_box (proj->priv->projectable);
gimp_projection_allocate_buffer (proj);
@@ -379,7 +377,9 @@ gimp_projection_get_buffer (GimpPickable *pickable)
* image appear incrementally, but it keeps everything
* responsive.
*/
- gimp_projection_add_update_area (proj, 0, 0, width, height);
+ gimp_projection_add_update_area (proj,
+ bounding_box.x, bounding_box.y,
+ bounding_box.width, bounding_box.height);
proj->priv->invalidate_preview = TRUE;
gimp_projection_flush (proj);
}
@@ -565,18 +565,17 @@ gimp_projection_finish_draw (GimpProjection *proj)
static void
gimp_projection_allocate_buffer (GimpProjection *proj)
{
- const Babl *format;
- gint width;
- gint height;
+ const Babl *format;
+ GeglRectangle bounding_box;
if (proj->priv->buffer)
return;
- format = gimp_projection_get_format (GIMP_PICKABLE (proj));
- gimp_projectable_get_size (proj->priv->projectable, &width, &height);
+ format = gimp_projection_get_format (GIMP_PICKABLE (proj));
+ bounding_box =
+ gimp_projectable_get_bounding_box (proj->priv->projectable);
- proj->priv->buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, width, height),
- format);
+ proj->priv->buffer = gegl_buffer_new (&bounding_box, format);
proj->priv->validate_handler =
GIMP_TILE_HANDLER_VALIDATE (
@@ -613,9 +612,9 @@ gimp_projection_add_update_area (GimpProjection *proj,
gint h)
{
cairo_rectangle_int_t rect;
- gint width, height;
+ GeglRectangle bounding_box;
- gimp_projectable_get_size (proj->priv->projectable, &width, &height);
+ bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
/* align the rectangle to the UPDATE_CHUNK_WIDTH x UPDATE_CHUNK_HEIGHT grid,
* to decrease the complexity of the update area.
@@ -628,9 +627,8 @@ gimp_projection_add_update_area (GimpProjection *proj,
w -= x;
h -= y;
- if (gimp_rectangle_intersect (x, y, w, h,
- 0, 0, width, height,
- &rect.x, &rect.y, &rect.width, &rect.height))
+ if (gegl_rectangle_intersect ((GeglRectangle *) &rect,
+ GEGL_RECTANGLE (x, y, w, h), &bounding_box))
{
if (proj->priv->update_region)
cairo_region_union_rectangle (proj->priv->update_region, &rect);
@@ -695,13 +693,13 @@ gimp_projection_update_priority_rect (GimpProjection *proj)
if (proj->priv->iter)
{
GeglRectangle rect;
+ GeglRectangle bounding_box;
gint off_x, off_y;
- gint width, height;
rect = proj->priv->priority_rect;
gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y);
- gimp_projectable_get_size (proj->priv->projectable, &width, &height);
+ bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
/* subtract the projectable's offsets because the list of update
* areas is in tile-pyramid coordinates, but our external API is
@@ -710,9 +708,7 @@ gimp_projection_update_priority_rect (GimpProjection *proj)
rect.x -= off_x;
rect.y -= off_y;
- gegl_rectangle_intersect (&rect,
- &rect,
- GEGL_RECTANGLE (0, 0, width, height));
+ gegl_rectangle_intersect (&rect, &rect, &bounding_box);
gimp_chunk_iterator_set_priority_rect (proj->priv->iter, &rect);
}
@@ -880,29 +876,29 @@ gimp_projection_paint_area (GimpProjection *proj,
gint w,
gint h)
{
- gint off_x, off_y;
- gint width, height;
+ gint off_x, off_y;
+ GeglRectangle bounding_box;
+ GeglRectangle rect;
gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y);
- gimp_projectable_get_size (proj->priv->projectable, &width, &height);
+ bounding_box = gimp_projectable_get_bounding_box (proj->priv->projectable);
- if (gimp_rectangle_intersect (x, y, w, h,
- 0, 0, width, height,
- &x, &y, &w, &h))
+ if (gegl_rectangle_intersect (&rect,
+ GEGL_RECTANGLE (x, y, w, h), &bounding_box))
{
if (now)
{
gimp_tile_handler_validate_validate (
proj->priv->validate_handler,
proj->priv->buffer,
- GEGL_RECTANGLE (x, y, w, h),
+ &rect,
FALSE);
}
else
{
gimp_tile_handler_validate_invalidate (
proj->priv->validate_handler,
- GEGL_RECTANGLE (x, y, w, h));
+ &rect);
}
/* add the projectable's offsets because the list of update areas
@@ -911,10 +907,10 @@ gimp_projection_paint_area (GimpProjection *proj,
*/
g_signal_emit (proj, projection_signals[UPDATE], 0,
now,
- x + off_x,
- y + off_y,
- w,
- h);
+ rect.x + off_x,
+ rect.y + off_y,
+ rect.width,
+ rect.height);
}
}
@@ -958,26 +954,31 @@ static void
gimp_projection_projectable_structure_changed (GimpProjectable *projectable,
GimpProjection *proj)
{
- gint width, height;
+ GeglRectangle bounding_box;
gimp_projection_free_buffer (proj);
- gimp_projectable_get_size (projectable, &width, &height);
+ bounding_box = gimp_projectable_get_bounding_box (projectable);
- gimp_projection_add_update_area (proj, 0, 0, width, height);
+ gimp_projection_add_update_area (proj,
+ bounding_box.x, bounding_box.y,
+ bounding_box.width, bounding_box.height);
}
static void
gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
gint old_x,
gint old_y,
- gint old_w,
- gint old_h,
GimpProjection *proj)
{
GeglBuffer *old_buffer = proj->priv->buffer;
GimpTileHandlerValidate *old_validate_handler;
- gint x, y, w, h;
+ GeglRectangle old_bounding_box;
+ GeglRectangle bounding_box;
+ GeglRectangle old_bounds;
+ GeglRectangle bounds;
+ GeglRectangle int_bounds;
+ gint x, y;
gint dx, dy;
if (! old_buffer)
@@ -987,23 +988,34 @@ gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
return;
}
+ old_bounding_box = *gegl_buffer_get_extent (old_buffer);
+
gimp_projectable_get_offset (projectable, &x, &y);
- gimp_projectable_get_size (projectable, &w, &h);
+ bounding_box = gimp_projectable_get_bounding_box (projectable);
- if (x == old_x && y == old_y && w == old_w && h == old_h)
- return;
+ if (x == old_x && y == old_y &&
+ gegl_rectangle_equal (&bounding_box, &old_bounding_box))
+ {
+ return;
+ }
+
+ old_bounds = old_bounding_box;
+ old_bounds.x += old_x;
+ old_bounds.y += old_y;
- if (! gimp_rectangle_intersect (x, y, w, h,
- old_x, old_y, old_w, old_h,
- NULL, NULL, NULL, NULL))
+ bounds = bounding_box;
+ bounds.x += x;
+ bounds.y += y;
+
+ if (! gegl_rectangle_intersect (&int_bounds, &bounds, &old_bounds))
{
gimp_projection_projectable_structure_changed (projectable, proj);
return;
}
- dx = old_x - x;
- dy = old_y - y;
+ dx = x - old_x;
+ dy = y - old_y;
#if 1
/* FIXME: when there's an offset between the new bounds and the old bounds,
@@ -1038,9 +1050,15 @@ gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
gimp_projection_allocate_buffer (proj);
gimp_tile_handler_validate_buffer_copy (old_buffer,
- GEGL_RECTANGLE (0, 0, old_w, old_h),
+ GEGL_RECTANGLE (int_bounds.x - old_x,
+ int_bounds.y - old_y,
+ int_bounds.width,
+ int_bounds.height),
proj->priv->buffer,
- GEGL_RECTANGLE (dx, dy, old_w, old_h));
+ GEGL_RECTANGLE (int_bounds.x - x,
+ int_bounds.y - y,
+ int_bounds.width,
+ int_bounds.height));
if (old_validate_handler)
{
@@ -1053,20 +1071,49 @@ gimp_projection_projectable_bounds_changed (GimpProjectable *projectable,
if (proj->priv->update_region)
{
- const cairo_rectangle_int_t bounds = {0, 0, w, h};
-
- cairo_region_translate (proj->priv->update_region, dx, dy);
- cairo_region_intersect_rectangle (proj->priv->update_region, &bounds);
+ cairo_region_translate (proj->priv->update_region, dx, dy);
+ cairo_region_intersect_rectangle (
+ proj->priv->update_region,
+ (const cairo_rectangle_int_t *) &bounding_box);
}
- if (dx > 0)
- gimp_projection_add_update_area (proj, 0, 0, dx, h);
- if (dy > 0)
- gimp_projection_add_update_area (proj, 0, 0, w, dy);
- if (dx + old_w < w)
- gimp_projection_add_update_area (proj, dx + old_w, 0, w - (dx + old_w), h);
- if (dy + old_h < h)
- gimp_projection_add_update_area (proj, 0, dy + old_h, w, h - (dy + old_h));
+ int_bounds.x -= x;
+ int_bounds.y -= y;
+
+ if (int_bounds.x > bounding_box.x)
+ {
+ gimp_projection_add_update_area (proj,
+ bounding_box.x,
+ bounding_box.y,
+ int_bounds.x - bounding_box.x,
+ bounding_box.height);
+ }
+ if (int_bounds.y > bounding_box.y)
+ {
+ gimp_projection_add_update_area (proj,
+ bounding_box.x,
+ bounding_box.y,
+ bounding_box.width,
+ int_bounds.y - bounding_box.y);
+ }
+ if (int_bounds.x + int_bounds.width < bounding_box.x + bounding_box.width)
+ {
+ gimp_projection_add_update_area (proj,
+ int_bounds.x + int_bounds.width,
+ bounding_box.y,
+ bounding_box.x + bounding_box.width -
+ (int_bounds.x + int_bounds.width),
+ bounding_box.height);
+ }
+ if (int_bounds.y + int_bounds.height < bounding_box.y + bounding_box.height)
+ {
+ gimp_projection_add_update_area (proj,
+ bounding_box.x,
+ int_bounds.y + int_bounds.height,
+ bounding_box.width,
+ bounding_box.y + bounding_box.height -
+ (int_bounds.y + int_bounds.height));
+ }
proj->priv->invalidate_preview = TRUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]