diff --git a/app/actions/layers-commands.c b/app/actions/layers-commands.c index bc843129f2..586cc9699d 100644 --- a/app/actions/layers-commands.c +++ b/app/actions/layers-commands.c @@ -943,11 +943,47 @@ layers_merge_group_cmd_callback (GimpAction *action, for (iter2 = layers; iter2; iter2 = iter2->next) { + if (iter->data == iter2->data) + continue; + /* Do not merge a layer when we already merge one of its * ancestors. */ if (gimp_viewable_is_ancestor (iter2->data, iter->data)) break; + + /* Do not merge a layer which has a little sister (same + * parent and smaller index) or a little cousin (one of + * its ancestors is a little sister) of a pass-through + * group layer. + * These will be rendered and merged through the + * pass-through by definition. + */ + if (gimp_viewable_get_children (GIMP_VIEWABLE (iter2->data)) && + gimp_layer_get_mode (iter2->data) == GIMP_LAYER_MODE_PASS_THROUGH) + { + GimpLayer *pass_through_parent = gimp_layer_get_parent (iter2->data); + GimpLayer *cousin = iter->data; + gboolean ignore = FALSE; + + do + { + GimpLayer *cousin_parent = gimp_layer_get_parent (cousin); + + if (pass_through_parent == cousin_parent && + gimp_item_get_index (GIMP_ITEM (iter2->data)) < gimp_item_get_index (GIMP_ITEM (cousin))) + { + ignore = TRUE; + break; + } + + cousin = cousin_parent; + } + while (cousin != NULL); + + if (ignore) + break; + } } if (iter2 == NULL) diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c index 69429a62c8..e20a018415 100644 --- a/app/core/gimpimage-merge.c +++ b/app/core/gimpimage-merge.c @@ -412,6 +412,7 @@ gimp_image_merge_group_layer (GimpImage *image, { GimpLayer *parent; GimpLayer *layer; + gboolean is_pass_through = FALSE; gint index; g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL); @@ -425,28 +426,8 @@ gimp_image_merge_group_layer (GimpImage *image, parent = gimp_layer_get_parent (GIMP_LAYER (group)); index = gimp_item_get_index (GIMP_ITEM (group)); - /* if this is a pass-through group, change its mode to NORMAL *before* - * duplicating it, since PASS_THROUGH mode is invalid for regular layers. - * see bug #793714. - */ - if (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH) - { - GimpLayerColorSpace blend_space; - GimpLayerColorSpace composite_space; - GimpLayerCompositeMode composite_mode; - - /* keep the group's current blend space, composite space, and composite - * mode. - */ - blend_space = gimp_layer_get_blend_space (GIMP_LAYER (group)); - composite_space = gimp_layer_get_composite_space (GIMP_LAYER (group)); - composite_mode = gimp_layer_get_composite_mode (GIMP_LAYER (group)); - - gimp_layer_set_mode (GIMP_LAYER (group), GIMP_LAYER_MODE_NORMAL, TRUE); - gimp_layer_set_blend_space (GIMP_LAYER (group), blend_space, TRUE); - gimp_layer_set_composite_space (GIMP_LAYER (group), composite_space, TRUE); - gimp_layer_set_composite_mode (GIMP_LAYER (group), composite_mode, TRUE); - } + is_pass_through = (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH && + gimp_item_get_visible (GIMP_ITEM (group))); /* Merge down filter effects */ gimp_drawable_merge_filters (GIMP_DRAWABLE (group)); @@ -460,6 +441,39 @@ gimp_image_merge_group_layer (GimpImage *image, gimp_image_remove_layer (image, GIMP_LAYER (group), TRUE, NULL); gimp_image_add_layer (image, layer, parent, index, TRUE); + /* For pass-through group layers, we must remove all "big sister" + * layers, i.e. all layers on the same level below the newly merged + * layer, because their render is already integrated in the merged + * layer. Therefore keeping them would change the whole image's + * rendering. + */ + if (is_pass_through) + { + GimpContainer *stack; + GList *iter; + GList *new_selected = g_list_prepend (NULL, layer); + GList *to_remove = NULL; + gboolean remove = FALSE; + + if (parent) + stack = gimp_viewable_get_children (GIMP_VIEWABLE (parent)); + else + stack = gimp_image_get_layers (image); + + for (iter = gimp_item_stack_get_item_iter (GIMP_ITEM_STACK (stack)); iter; iter = iter->next) + { + if (iter->data == layer) + remove = TRUE; + else if (remove && gimp_item_get_visible (iter->data)) + to_remove = g_list_prepend (to_remove, iter->data); + } + + for (iter = to_remove; iter; iter = iter->next) + gimp_image_remove_layer (image, GIMP_LAYER (iter->data), TRUE, new_selected); + + g_list_free (new_selected); + } + gimp_image_undo_group_end (image); return layer; diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c index 3fed5241fe..ff856fec25 100644 --- a/app/core/gimplayer.c +++ b/app/core/gimplayer.c @@ -937,16 +937,46 @@ gimp_layer_duplicate (GimpItem *item, GimpLayer *layer = GIMP_LAYER (item); GimpLayer *new_layer = GIMP_LAYER (new_item); - gimp_layer_set_mode (new_layer, - gimp_layer_get_mode (layer), FALSE); - gimp_layer_set_blend_space (new_layer, - gimp_layer_get_blend_space (layer), FALSE); - gimp_layer_set_composite_space (new_layer, - gimp_layer_get_composite_space (layer), FALSE); - gimp_layer_set_composite_mode (new_layer, - gimp_layer_get_composite_mode (layer), FALSE); - gimp_layer_set_opacity (new_layer, - gimp_layer_get_opacity (layer), FALSE); + /* PASS_THROUGH mode is invalid for regular layers. + * We used to change the mode to NORMAL *before* duplicating (see + * #793714 on bugzilla) but it would change the image's render. + * Instead we first duplicate so that the group's render is used + * as-is for the non-group duplicate layer. Then we set NORMAL + * mode. + */ + if (gimp_layer_get_mode (layer) == GIMP_LAYER_MODE_PASS_THROUGH && + ! GIMP_IS_GROUP_LAYER (new_item)) + { + GimpLayerColorSpace blend_space; + GimpLayerColorSpace composite_space; + GimpLayerCompositeMode composite_mode; + + /* keep the group's current blend space, composite space, and composite + * mode. + */ + blend_space = gimp_layer_get_blend_space (layer); + composite_space = gimp_layer_get_composite_space (layer); + composite_mode = gimp_layer_get_composite_mode (layer); + + gimp_layer_set_mode (new_layer, GIMP_LAYER_MODE_NORMAL, FALSE); + gimp_layer_set_blend_space (new_layer, blend_space, FALSE); + gimp_layer_set_composite_space (new_layer, composite_space, FALSE); + gimp_layer_set_composite_mode (new_layer, composite_mode, FALSE); + gimp_layer_set_opacity (new_layer, 1.0, FALSE); + } + else + { + gimp_layer_set_mode (new_layer, + gimp_layer_get_mode (layer), FALSE); + gimp_layer_set_blend_space (new_layer, + gimp_layer_get_blend_space (layer), FALSE); + gimp_layer_set_composite_space (new_layer, + gimp_layer_get_composite_space (layer), FALSE); + gimp_layer_set_composite_mode (new_layer, + gimp_layer_get_composite_mode (layer), FALSE); + gimp_layer_set_opacity (new_layer, + gimp_layer_get_opacity (layer), FALSE); + } if (gimp_layer_can_lock_alpha (new_layer)) gimp_layer_set_lock_alpha (new_layer,