From 9c288f9e08c90b943349ea6e8cf7ccefa2c8111c Mon Sep 17 00:00:00 2001 From: Thomas Holder Date: Wed, 28 Oct 2020 21:03:19 +0100 Subject: [PATCH 1/2] Refactor: _ungroup_compensate_source_transform --- src/object/sp-item-group.cpp | 84 +++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/src/object/sp-item-group.cpp b/src/object/sp-item-group.cpp index 201a6dcc94..8cff0e8bfe 100644 --- a/src/object/sp-item-group.cpp +++ b/src/object/sp-item-group.cpp @@ -381,6 +381,48 @@ void sp_item_group_ungroup_handle_clones(SPItem *parent, Geom::Affine const g) } } +/** + * Helper function for ungrouping. Compensates the transform of linked items + * (linked offset, text-on-path, text with shape-inside) who's source is a + * direct child of the group being ungrouped. + */ +static void _ungroup_compensate_source_transform(SPItem *item, SPGroup const *group, Geom::Affine const &g) +{ + SPItem *source = nullptr; + SPText *item_text = nullptr; + SPOffset *item_offset = nullptr; + + if ((item_offset = dynamic_cast(item))) { + // When dealing with a chain of linked offsets, the transformation of an offset will be + // tied to the transformation of the top-most source, not to any of the intermediate + // offsets. So let's find the top-most source + auto offset = item_offset; + do { + source = sp_offset_get_source(offset); + } while ((offset = dynamic_cast(source))); + } else if ((item_text = dynamic_cast(item))) { + source = item_text->get_first_shape_dependency(); + } + + // FIXME: constructing a transform that would fully preserve the appearance of a + // textpath if it is ungrouped with its path seems to be impossible in general + // case. E.g. if the group was squeezed, to keep the ungrouped textpath squeezed + // as well, we'll need to relink it to some "virtual" path which is inversely + // stretched relative to the actual path, and then squeeze the textpath back so it + // would both fit the actual path _and_ be squeezed as before. It's a bummer. + + if (source && group->isAncestorOf(source)) { + double const scale = g.descrim(); + if (item_text) { + item_text->_adjustFontsizeRecursive(item_text, scale); + } else if (item_offset) { + item_offset->rad *= scale; + } + item->adjust_stroke_width_recursive(scale); + item->transform = g.inverse() * item->transform; + } +} + void sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_done) { @@ -455,47 +497,9 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d */ // Merging transform - Geom::Affine ctrans = citem->transform * g; - - SPItem *source = nullptr; - SPText *citem_text = nullptr; - SPOffset *citem_offset = nullptr; - - // We should not apply the group's transformation to both a linked offset AND to its source - if ((citem_offset = dynamic_cast(citem))) { - // When dealing with a chain of linked offsets, the transformation of an offset will be - // tied to the transformation of the top-most source, not to any of the intermediate - // offsets. So let's find the top-most source - auto offset = citem_offset; - do { - source = sp_offset_get_source(offset); - } while ((offset = dynamic_cast(source))); - } else if ((citem_text = dynamic_cast(citem))) { - source = citem_text->get_first_shape_dependency(); - } + citem->transform *= g; - // FIXME: constructing a transform that would fully preserve the appearance of a - // textpath if it is ungrouped with its path seems to be impossible in general - // case. E.g. if the group was squeezed, to keep the ungrouped textpath squeezed - // as well, we'll need to relink it to some "virtual" path which is inversely - // stretched relative to the actual path, and then squeeze the textpath back so it - // would both fit the actual path _and_ be squeezed as before. It's a bummer. - - // This is just a way to temporarily remember the transform in repr. When repr is - // reattached outside of the group, the transform will be written more properly - // (i.e. optimized into the object if the corresponding preference is set) - if (source && group->isAncestorOf(source)) { - double const scale = g.descrim(); - if (citem_text) { - citem_text->_adjustFontsizeRecursive(citem_text, scale); - } else if (citem_offset) { - citem_offset->rad *= scale; - } - citem->adjust_stroke_width_recursive(scale); - citem->transform = g.inverse() * ctrans; - } else { - citem->transform = ctrans; - } + _ungroup_compensate_source_transform(citem, group, g); child.updateRepr(); -- GitLab From 470e76487abbcb7578e4de8a0c814a8e82091a5c Mon Sep 17 00:00:00 2001 From: Thomas Holder Date: Wed, 28 Oct 2020 21:04:01 +0100 Subject: [PATCH 2/2] Fix ungrouping: linked grand-children, grand-child source Transform of linked items (linked offset, text-on-path, text with shape-inside) must only be compensated if their source is a direct child of the group being ungrouped. This also applies to linked items which are not direct children of the group. --- src/object/sp-item-group.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/object/sp-item-group.cpp b/src/object/sp-item-group.cpp index 8cff0e8bfe..8da949ff44 100644 --- a/src/object/sp-item-group.cpp +++ b/src/object/sp-item-group.cpp @@ -402,6 +402,12 @@ static void _ungroup_compensate_source_transform(SPItem *item, SPGroup const *gr } while ((offset = dynamic_cast(source))); } else if ((item_text = dynamic_cast(item))) { source = item_text->get_first_shape_dependency(); + } else if (auto item_group = dynamic_cast(item)) { + for (auto &child : item_group->children) { + if (SPItem *citem = dynamic_cast(&child)) { + _ungroup_compensate_source_transform(citem, group, g); + } + } } // FIXME: constructing a transform that would fully preserve the appearance of a @@ -411,7 +417,7 @@ static void _ungroup_compensate_source_transform(SPItem *item, SPGroup const *gr // stretched relative to the actual path, and then squeeze the textpath back so it // would both fit the actual path _and_ be squeezed as before. It's a bummer. - if (source && group->isAncestorOf(source)) { + if (source && group == source->parent) { double const scale = g.descrim(); if (item_text) { item_text->_adjustFontsizeRecursive(item_text, scale); -- GitLab