Commit c83f0e88 authored by Ell's avatar Ell

app: add virtual transform/type-conversion functions to GimpLayer

The GimpLayer implementation of the GimpItem transform functions,
and the GimpDrawable convert_type() function, apply their operation
to both the layer and its mask.  The subclasses of GimpLayer --
GimpGroupLayer and GimpTextLayer -- override some of these
functions, providing their own logic for the layer part, and
duplicating the mask part.

Avoid this duplication by adding a set of virtual transform and
type-conversion functions to GimpLayer.  Have the GimpLayer
implementaion of the corresponding GimpItem and GimpDrawable
functions use these functions to apply the operation to the layer,
while taking care of the mask themselves.  Have GimpLayer's
subclasses override the new virtual functions, instead of the
GimpItem and GimpDrawable ones.

Note that the existing implementation of convert_type() in
GimpTextLayer neglected to convert the mask, hence text layer masks
retained their old format after conversion.  This issue is fixed as
a side effect of this commit.
parent 40dccbdd
This diff is collapsed.
......@@ -210,6 +210,49 @@ static void gimp_layer_srgb_to_pixel (GimpPickable *pickable,
const Babl *format,
gpointer pixel);
static void gimp_layer_real_translate (GimpLayer *layer,
gint offset_x,
gint offset_y);
static void gimp_layer_real_scale (GimpLayer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y,
GimpInterpolationType interp_type,
GimpProgress *progress);
static void gimp_layer_real_resize (GimpLayer *layer,
GimpContext *context,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y);
static void gimp_layer_real_flip (GimpLayer *layer,
GimpContext *context,
GimpOrientationType flip_type,
gdouble axis,
gboolean clip_result);
static void gimp_layer_real_rotate (GimpLayer *layer,
GimpContext *context,
GimpRotationType rotate_type,
gdouble center_x,
gdouble center_y,
gboolean clip_result);
static void gimp_layer_real_transform (GimpLayer *layer,
GimpContext *context,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
static void gimp_layer_real_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress);
static gboolean
gimp_layer_real_get_excludes_backdrop (GimpLayer *layer);
......@@ -406,6 +449,13 @@ gimp_layer_class_init (GimpLayerClass *klass)
klass->apply_mask_changed = NULL;
klass->edit_mask_changed = NULL;
klass->show_mask_changed = NULL;
klass->translate = gimp_layer_real_translate;
klass->scale = gimp_layer_real_scale;
klass->resize = gimp_layer_real_resize;
klass->flip = gimp_layer_real_flip;
klass->rotate = gimp_layer_real_rotate;
klass->transform = gimp_layer_real_transform;
klass->convert_type = gimp_layer_real_convert_type;
klass->get_excludes_backdrop = gimp_layer_real_get_excludes_backdrop;
g_object_class_install_property (object_class, PROP_OPACITY,
......@@ -995,17 +1045,7 @@ gimp_layer_translate (GimpItem *item,
if (push_undo)
gimp_image_undo_push_item_displace (gimp_item_get_image (item), NULL, item);
/* update the old region */
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
/* invalidate the selection boundary because of a layer modification */
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer));
GIMP_ITEM_CLASS (parent_class)->translate (item, offset_x, offset_y,
push_undo);
/* update the new region */
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
GIMP_LAYER_GET_CLASS (layer)->translate (layer, offset_x, offset_y);
if (layer->mask)
{
......@@ -1029,9 +1069,9 @@ gimp_layer_scale (GimpItem *item,
{
GimpLayer *layer = GIMP_LAYER (item);
GIMP_ITEM_CLASS (parent_class)->scale (item, new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
GIMP_LAYER_GET_CLASS (layer)->scale (layer, new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
if (layer->mask)
gimp_item_scale (GIMP_ITEM (layer->mask),
......@@ -1051,15 +1091,9 @@ gimp_layer_resize (GimpItem *item,
{
GimpLayer *layer = GIMP_LAYER (item);
if (fill_type == GIMP_FILL_TRANSPARENT &&
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
{
fill_type = GIMP_FILL_BACKGROUND;
}
GIMP_ITEM_CLASS (parent_class)->resize (item, context, fill_type,
new_width, new_height,
offset_x, offset_y);
GIMP_LAYER_GET_CLASS (layer)->resize (layer, context, fill_type,
new_width, new_height,
offset_x, offset_y);
if (layer->mask)
gimp_item_resize (GIMP_ITEM (layer->mask), context, GIMP_FILL_TRANSPARENT,
......@@ -1075,8 +1109,8 @@ gimp_layer_flip (GimpItem *item,
{
GimpLayer *layer = GIMP_LAYER (item);
GIMP_ITEM_CLASS (parent_class)->flip (item, context, flip_type, axis,
clip_result);
GIMP_LAYER_GET_CLASS (layer)->flip (layer, context, flip_type, axis,
clip_result);
if (layer->mask)
gimp_item_flip (GIMP_ITEM (layer->mask), context,
......@@ -1093,9 +1127,9 @@ gimp_layer_rotate (GimpItem *item,
{
GimpLayer *layer = GIMP_LAYER (item);
GIMP_ITEM_CLASS (parent_class)->rotate (item, context,
rotate_type, center_x, center_y,
clip_result);
GIMP_LAYER_GET_CLASS (layer)->rotate (layer, context,
rotate_type, center_x, center_y,
clip_result);
if (layer->mask)
gimp_item_rotate (GIMP_ITEM (layer->mask), context,
......@@ -1113,15 +1147,10 @@ gimp_layer_transform (GimpItem *item,
{
GimpLayer *layer = GIMP_LAYER (item);
/* FIXME: make interpolated transformations work on layers without alpha */
if (interpolation_type != GIMP_INTERPOLATION_NONE &&
! gimp_drawable_has_alpha (GIMP_DRAWABLE (item)))
gimp_layer_add_alpha (layer);
GIMP_ITEM_CLASS (parent_class)->transform (item, context, matrix, direction,
interpolation_type,
clip_result,
progress);
GIMP_LAYER_GET_CLASS (layer)->transform (layer, context, matrix, direction,
interpolation_type,
clip_result,
progress);
if (layer->mask)
gimp_item_transform (GIMP_ITEM (layer->mask), context,
......@@ -1190,57 +1219,12 @@ gimp_layer_convert_type (GimpDrawable *drawable,
gboolean push_undo,
GimpProgress *progress)
{
GimpLayer *layer = GIMP_LAYER (drawable);
GeglBuffer *src_buffer;
GeglBuffer *dest_buffer;
if (layer_dither_type == GEGL_DITHER_NONE)
{
src_buffer = g_object_ref (gimp_drawable_get_buffer (drawable));
}
else
{
gint bits;
src_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)),
gimp_item_get_height (GIMP_ITEM (drawable))),
gimp_drawable_get_format (drawable));
bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
babl_format_get_n_components (new_format));
gimp_gegl_apply_dither (gimp_drawable_get_buffer (drawable),
NULL, NULL,
src_buffer, 1 << bits, layer_dither_type);
}
dest_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (GIMP_ITEM (drawable)),
gimp_item_get_height (GIMP_ITEM (drawable))),
new_format);
if (dest_profile)
{
GimpColorProfile *src_profile =
gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer));
GimpLayer *layer = GIMP_LAYER (drawable);
gimp_gegl_convert_color_profile (src_buffer, NULL, src_profile,
dest_buffer, NULL, dest_profile,
GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
TRUE, progress);
}
else
{
gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE, dest_buffer, NULL);
}
gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
g_object_unref (src_buffer);
g_object_unref (dest_buffer);
GIMP_LAYER_GET_CLASS (layer)->convert_type (layer, dest_image, new_format,
dest_profile, layer_dither_type,
mask_dither_type, push_undo,
progress);
if (layer->mask &&
gimp_babl_format_get_precision (new_format) !=
......@@ -1403,6 +1387,170 @@ gimp_layer_srgb_to_pixel (GimpPickable *pickable,
gimp_pickable_srgb_to_pixel (GIMP_PICKABLE (image), color, format, pixel);
}
static void
gimp_layer_real_translate (GimpLayer *layer,
gint offset_x,
gint offset_y)
{
/* update the old region */
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
/* invalidate the selection boundary because of a layer modification */
gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer));
GIMP_ITEM_CLASS (parent_class)->translate (GIMP_ITEM (layer),
offset_x, offset_y,
FALSE);
/* update the new region */
gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, -1, -1);
}
static void
gimp_layer_real_scale (GimpLayer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y,
GimpInterpolationType interpolation_type,
GimpProgress *progress)
{
GIMP_ITEM_CLASS (parent_class)->scale (GIMP_ITEM (layer),
new_width, new_height,
new_offset_x, new_offset_y,
interpolation_type, progress);
}
static void
gimp_layer_real_resize (GimpLayer *layer,
GimpContext *context,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y)
{
if (fill_type == GIMP_FILL_TRANSPARENT &&
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
{
fill_type = GIMP_FILL_BACKGROUND;
}
GIMP_ITEM_CLASS (parent_class)->resize (GIMP_ITEM (layer),
context, fill_type,
new_width, new_height,
offset_x, offset_y);
}
static void
gimp_layer_real_flip (GimpLayer *layer,
GimpContext *context,
GimpOrientationType flip_type,
gdouble axis,
gboolean clip_result)
{
GIMP_ITEM_CLASS (parent_class)->flip (GIMP_ITEM (layer),
context, flip_type, axis, clip_result);
}
static void
gimp_layer_real_rotate (GimpLayer *layer,
GimpContext *context,
GimpRotationType rotate_type,
gdouble center_x,
gdouble center_y,
gboolean clip_result)
{
GIMP_ITEM_CLASS (parent_class)->rotate (GIMP_ITEM (layer),
context, rotate_type,
center_x, center_y,
clip_result);
}
static void
gimp_layer_real_transform (GimpLayer *layer,
GimpContext *context,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress)
{
/* FIXME: make interpolated transformations work on layers without alpha */
if (interpolation_type != GIMP_INTERPOLATION_NONE &&
! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer)))
gimp_layer_add_alpha (layer);
GIMP_ITEM_CLASS (parent_class)->transform (GIMP_ITEM (layer),
context, matrix, direction,
interpolation_type,
clip_result,
progress);
}
static void
gimp_layer_real_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress)
{
GimpDrawable *drawable = GIMP_DRAWABLE (layer);
GeglBuffer *src_buffer;
GeglBuffer *dest_buffer;
if (layer_dither_type == GEGL_DITHER_NONE)
{
src_buffer = g_object_ref (gimp_drawable_get_buffer (drawable));
}
else
{
gint bits;
src_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (GIMP_ITEM (layer)),
gimp_item_get_height (GIMP_ITEM (layer))),
gimp_drawable_get_format (drawable));
bits = (babl_format_get_bytes_per_pixel (new_format) * 8 /
babl_format_get_n_components (new_format));
gimp_gegl_apply_dither (gimp_drawable_get_buffer (drawable),
NULL, NULL,
src_buffer, 1 << bits, layer_dither_type);
}
dest_buffer =
gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_item_get_width (GIMP_ITEM (layer)),
gimp_item_get_height (GIMP_ITEM (layer))),
new_format);
if (dest_profile)
{
GimpColorProfile *src_profile =
gimp_color_managed_get_color_profile (GIMP_COLOR_MANAGED (layer));
gimp_gegl_convert_color_profile (src_buffer, NULL, src_profile,
dest_buffer, NULL, dest_profile,
GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
TRUE, progress);
}
else
{
gegl_buffer_copy (src_buffer, NULL, GEGL_ABYSS_NONE, dest_buffer, NULL);
}
gimp_drawable_set_buffer (drawable, push_undo, NULL, dest_buffer);
g_object_unref (src_buffer);
g_object_unref (dest_buffer);
}
static gboolean
gimp_layer_real_get_excludes_backdrop (GimpLayer *layer)
{
......
......@@ -67,20 +67,63 @@ struct _GimpLayerClass
GimpDrawableClass parent_class;
/* signals */
void (* opacity_changed) (GimpLayer *layer);
void (* mode_changed) (GimpLayer *layer);
void (* blend_space_changed) (GimpLayer *layer);
void (* composite_space_changed) (GimpLayer *layer);
void (* composite_mode_changed) (GimpLayer *layer);
void (* excludes_backdrop_changed) (GimpLayer *layer);
void (* lock_alpha_changed) (GimpLayer *layer);
void (* mask_changed) (GimpLayer *layer);
void (* apply_mask_changed) (GimpLayer *layer);
void (* edit_mask_changed) (GimpLayer *layer);
void (* show_mask_changed) (GimpLayer *layer);
void (* opacity_changed) (GimpLayer *layer);
void (* mode_changed) (GimpLayer *layer);
void (* blend_space_changed) (GimpLayer *layer);
void (* composite_space_changed) (GimpLayer *layer);
void (* composite_mode_changed) (GimpLayer *layer);
void (* excludes_backdrop_changed) (GimpLayer *layer);
void (* lock_alpha_changed) (GimpLayer *layer);
void (* mask_changed) (GimpLayer *layer);
void (* apply_mask_changed) (GimpLayer *layer);
void (* edit_mask_changed) (GimpLayer *layer);
void (* show_mask_changed) (GimpLayer *layer);
/* virtual functions */
gboolean (* get_excludes_backdrop) (GimpLayer *layer);
void (* translate) (GimpLayer *layer,
gint offset_x,
gint offset_y);
void (* scale) (GimpLayer *layer,
gint new_width,
gint new_height,
gint new_offset_x,
gint new_offset_y,
GimpInterpolationType interpolation_type,
GimpProgress *progress);
void (* resize) (GimpLayer *layer,
GimpContext *context,
GimpFillType fill_type,
gint new_width,
gint new_height,
gint offset_x,
gint offset_y);
void (* flip) (GimpLayer *layer,
GimpContext *context,
GimpOrientationType flip_type,
gdouble axis,
gboolean clip_result);
void (* rotate) (GimpLayer *layer,
GimpContext *context,
GimpRotationType rotate_type,
gdouble center_x,
gdouble center_y,
gboolean clip_result);
void (* transform) (GimpLayer *layer,
GimpContext *context,
const GimpMatrix3 *matrix,
GimpTransformDirection direction,
GimpInterpolationType interpolation_type,
GimpTransformResize clip_result,
GimpProgress *progress);
void (* convert_type) (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress);
gboolean (* get_excludes_backdrop) (GimpLayer *layer);
};
......
......@@ -85,14 +85,6 @@ static gboolean gimp_text_layer_rename (GimpItem *item,
const gchar *undo_desc,
GError **error);
static void gimp_text_layer_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress);
static void gimp_text_layer_set_buffer (GimpDrawable *drawable,
gboolean push_undo,
const gchar *undo_desc,
......@@ -107,6 +99,15 @@ static void gimp_text_layer_push_undo (GimpDrawable *drawable,
gint width,
gint height);
static void gimp_text_layer_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress);
static void gimp_text_layer_text_changed (GimpTextLayer *layer);
static gboolean gimp_text_layer_render (GimpTextLayer *layer);
static void gimp_text_layer_render_layout (GimpTextLayer *layer,
......@@ -126,6 +127,7 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass)
GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass);
GimpItemClass *item_class = GIMP_ITEM_CLASS (klass);
GimpDrawableClass *drawable_class = GIMP_DRAWABLE_CLASS (klass);
GimpLayerClass *layer_class = GIMP_LAYER_CLASS (klass);
object_class->finalize = gimp_text_layer_finalize;
object_class->get_property = gimp_text_layer_get_property;
......@@ -154,10 +156,11 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass)
item_class->rotate_desc = _("Rotate Text Layer");
item_class->transform_desc = _("Transform Text Layer");
drawable_class->convert_type = gimp_text_layer_convert_type;
drawable_class->set_buffer = gimp_text_layer_set_buffer;
drawable_class->push_undo = gimp_text_layer_push_undo;
layer_class->convert_type = gimp_text_layer_convert_type;
GIMP_CONFIG_PROP_OBJECT (object_class, PROP_TEXT,
"text",
NULL, NULL,
......@@ -314,44 +317,6 @@ gimp_text_layer_rename (GimpItem *item,
return FALSE;
}
static void
gimp_text_layer_convert_type (GimpDrawable *drawable,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress)
{
GimpTextLayer *layer = GIMP_TEXT_LAYER (drawable);
GimpImage *image = gimp_item_get_image (GIMP_ITEM (layer));
if (! layer->text ||
layer->modified ||
layer_dither_type != GEGL_DITHER_NONE)
{
GIMP_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image,
new_format,
dest_profile,
layer_dither_type,
mask_dither_type,
push_undo,
progress);
}
else
{
if (push_undo)
gimp_image_undo_push_text_layer_convert (image, NULL, layer);
layer->convert_format = new_format;
gimp_text_layer_render (layer);
layer->convert_format = NULL;
}
}
static void
gimp_text_layer_set_buffer (GimpDrawable *drawable,
gboolean push_undo,
......@@ -411,6 +376,44 @@ gimp_text_layer_push_undo (GimpDrawable *drawable,
}
}
static void
gimp_text_layer_convert_type (GimpLayer *layer,
GimpImage *dest_image,
const Babl *new_format,
GimpColorProfile *dest_profile,
GeglDitherMethod layer_dither_type,
GeglDitherMethod mask_dither_type,
gboolean push_undo,
GimpProgress *progress)
{
GimpTextLayer *text_layer = GIMP_TEXT_LAYER (layer);
GimpImage *image = gimp_item_get_image (GIMP_ITEM (text_layer));
if (! text_layer->text ||
text_layer->modified ||
layer_dither_type != GEGL_DITHER_NONE)
{
GIMP_LAYER_CLASS (parent_class)->convert_type (layer, dest_image,
new_format,
dest_profile,
layer_dither_type,
mask_dither_type,
push_undo,
progress);
}
else
{
if (push_undo)
gimp_image_undo_push_text_layer_convert (image, NULL, text_layer);
text_layer->convert_format = new_format;
gimp_text_layer_render (text_layer);
text_layer->convert_format = NULL;
}
}
/* public functions */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment