File indexing completed on 2024-05-19 04:26:21

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_layer_utils.h"
0008 
0009 #include <algorithm>
0010 
0011 #include <QUuid>
0012 #include <KoColorSpaceConstants.h>
0013 #include <KoProperties.h>
0014 
0015 #include "kis_painter.h"
0016 #include "kis_image.h"
0017 #include "kis_node.h"
0018 #include "kis_layer.h"
0019 #include "kis_paint_layer.h"
0020 #include "kis_clone_layer.h"
0021 #include "kis_group_layer.h"
0022 #include "kis_selection.h"
0023 #include "kis_selection_mask.h"
0024 #include "kis_meta_data_merge_strategy.h"
0025 #include <kundo2command.h>
0026 #include "commands/kis_image_layer_add_command.h"
0027 #include "commands/kis_image_layer_remove_command.h"
0028 #include "commands/kis_image_layer_move_command.h"
0029 #include "commands/kis_image_change_layers_command.h"
0030 #include "commands_new/kis_activate_selection_mask_command.h"
0031 #include "commands/kis_image_change_visibility_command.h"
0032 #include "kis_abstract_projection_plane.h"
0033 #include "kis_processing_applicator.h"
0034 #include "kis_image_animation_interface.h"
0035 #include "kis_keyframe_channel.h"
0036 #include "kis_raster_keyframe_channel.h"
0037 #include "kis_projection_leaf.h"
0038 #include "kis_scalar_keyframe_channel.h"
0039 #include "kis_time_span.h"
0040 #include "kis_command_utils.h"
0041 #include "commands_new/kis_change_projection_color_command.h"
0042 #include "kis_layer_properties_icons.h"
0043 #include "lazybrush/kis_colorize_mask.h"
0044 #include "commands/kis_node_property_list_command.h"
0045 #include "commands/kis_node_compositeop_command.h"
0046 #include <KisDelayedUpdateNodeInterface.h>
0047 #include <KisCroppedOriginalLayerInterface.h>
0048 #include "krita_utils.h"
0049 #include "kis_image_signal_router.h"
0050 #include "kis_sequential_iterator.h"
0051 #include "kis_transparency_mask.h"
0052 #include "kis_paint_device_frames_interface.h"
0053 #include "kis_command_ids.h"
0054 #include "kis_image_config.h"
0055 #include "KisFutureUtils.h"
0056 
0057 
0058 namespace KisLayerUtils {
0059 
0060 namespace Private {
0061     void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea, const QRect &extraUpdateRect);
0062 }
0063 
0064     void fetchSelectionMasks(KisNodeList mergedNodes, QVector<KisSelectionMaskSP> &selectionMasks)
0065     {
0066         foreach (KisNodeSP node, mergedNodes) {
0067 
0068             Q_FOREACH(KisNodeSP child, node->childNodes(QStringList("KisSelectionMask"), KoProperties())) {
0069 
0070                 KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(child.data());
0071                 if (mask) {
0072                     selectionMasks.append(mask);
0073                 }
0074             }
0075         }
0076     }
0077 
0078     struct MergeDownInfoBase {
0079         MergeDownInfoBase(KisImageSP _image)
0080             : image(_image),
0081               storage(new SwitchFrameCommand::SharedStorage())
0082         {
0083         }
0084 
0085         virtual ~MergeDownInfoBase() {}
0086 
0087         KisImageWSP image;
0088 
0089         QVector<KisSelectionMaskSP> selectionMasks;
0090 
0091         KisNodeSP dstNode;
0092 
0093         SwitchFrameCommand::SharedStorageSP storage;
0094         QSet<int> frames;
0095         bool pinnedToTimeline = false;
0096         bool enableOnionSkins = false;
0097 
0098         virtual KisNodeList allSrcNodes() = 0;
0099 
0100         KisLayerSP dstLayer() {
0101             return qobject_cast<KisLayer*>(dstNode.data());
0102         }
0103     };
0104 
0105     struct SplitAlphaToMaskInfo {
0106         SplitAlphaToMaskInfo(KisImageSP _image, KisNodeSP _node, const QString& maskName)
0107             : image(_image)
0108             , node(_node)
0109             , storage(new SwitchFrameCommand::SharedStorage())
0110         {
0111             frames = fetchLayerFramesRecursive(_node);
0112             mask = new KisTransparencyMask(image, maskName);
0113         }
0114 
0115         KisImageWSP image;
0116         KisNodeSP node;
0117         SwitchFrameCommand::SharedStorageSP storage;
0118         QSet<int> frames;
0119 
0120         KisPaintDeviceSP getMaskDevice() {
0121             return mask->paintDevice();
0122         }
0123 
0124         KisMaskSP getMask() {
0125             return mask;
0126         }
0127 
0128         KisLayerSP getLayer() {
0129             return qobject_cast<KisLayer*>(node.data());
0130         }
0131 
0132     private:
0133         KisTransparencyMaskSP mask;
0134 
0135     };
0136 
0137     struct MergeDownInfo : public MergeDownInfoBase {
0138         MergeDownInfo(KisImageSP _image,
0139                       KisLayerSP _prevLayer,
0140                       KisLayerSP _currLayer)
0141             : MergeDownInfoBase(_image),
0142               prevLayer(_prevLayer),
0143               currLayer(_currLayer)
0144         {
0145             frames = fetchLayerFramesRecursive(prevLayer) |
0146                 fetchLayerFramesRecursive(currLayer);
0147 
0148             /**
0149              * If source layer is not animated, then just merge that into the current frame
0150              * only. See the other part of this feature in mergeDown() itself
0151              *
0152              * See https://bugs.kde.org/show_bug.cgi?id=475550
0153              */
0154             if (!frames.isEmpty() && !currLayer->isAnimated()) {
0155                 frames.insert(image->animationInterface()->currentTime());
0156             }
0157 
0158             pinnedToTimeline = prevLayer->isPinnedToTimeline() || currLayer->isPinnedToTimeline();
0159 
0160             const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(currLayer.data());
0161             if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled();
0162 
0163             paintLayer = qobject_cast<KisPaintLayer*>(prevLayer.data());
0164             if (paintLayer) enableOnionSkins |= paintLayer->onionSkinEnabled();
0165         }
0166 
0167         KisLayerSP prevLayer;
0168         KisLayerSP currLayer;
0169 
0170         KisNodeList allSrcNodes() override {
0171             KisNodeList mergedNodes;
0172             mergedNodes << prevLayer;
0173             mergedNodes << currLayer;
0174             return mergedNodes;
0175         }
0176     };
0177 
0178     struct ConvertToPaintLayerInfo {
0179         ConvertToPaintLayerInfo(KisImageSP image, KisNodeSP node)
0180             : storage(new SwitchFrameCommand::SharedStorage())
0181             , m_sourceNode(node)
0182             , m_image(image)
0183             , m_pinnedToTimeline(false)
0184         {
0185             m_frames = fetchLayerFramesRecursive(node);
0186 
0187             m_pinnedToTimeline = node->isPinnedToTimeline();
0188 
0189             m_sourcePaintDevice =
0190                     m_sourceNode->paintDevice() ? m_sourceNode->projection() : m_sourceNode->original();
0191 
0192             m_compositeOp = m_sourceNode->projectionLeaf()->isLayer() ? m_sourceNode->compositeOpId() : COMPOSITE_OVER;
0193 
0194             KisColorizeMask *colorizeMask = dynamic_cast<KisColorizeMask*>(m_sourceNode.data());
0195             if (colorizeMask) {
0196                 m_sourcePaintDevice = colorizeMask->coloringProjection();
0197                 const bool putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND;
0198                 if (putBehind) {
0199                     m_compositeOp = COMPOSITE_OVER;
0200                 }
0201 
0202                 m_insertionParent = m_sourceNode->parent()->parent();
0203                 m_insertionPutAfter = putBehind ? m_sourceNode->parent()->prevSibling() : m_sourceNode->parent();
0204 
0205             } else if (dynamic_cast<KisMask*>(m_sourceNode.data())) {
0206                 m_insertionParent = m_sourceNode->parent()->parent();
0207                 m_insertionPutAfter = m_sourceNode->parent()->prevSibling();
0208             } else {
0209                 m_insertionParent = m_sourceNode->parent();
0210                 m_insertionPutAfter = m_sourceNode;
0211             }
0212 
0213             KisCloneLayer *cloneLayer = dynamic_cast<KisCloneLayer*>(m_sourceNode.data());
0214             if (cloneLayer) {
0215                 m_targetNode = cloneLayer->reincarnateAsPaintLayer();
0216             } else if (m_sourcePaintDevice) {
0217                 KisPaintDeviceSP clone;
0218 
0219                 if (*m_sourcePaintDevice->colorSpace() !=
0220                         *m_sourcePaintDevice->compositionSourceColorSpace()) {
0221 
0222                     clone = new KisPaintDevice(m_sourcePaintDevice->compositionSourceColorSpace());
0223                     clone->setDefaultPixel(
0224                         m_sourcePaintDevice->defaultPixel().convertedTo(
0225                             m_sourcePaintDevice->compositionSourceColorSpace()));
0226 
0227                     QRect rc(m_sourcePaintDevice->extent());
0228                     KisPainter::copyAreaOptimized(rc.topLeft(), m_sourcePaintDevice, clone, rc);
0229                 } else {
0230                     clone = new KisPaintDevice(*m_sourcePaintDevice);
0231                 }
0232 
0233                 m_targetNode = new KisPaintLayer(m_image,
0234                                                      m_sourceNode->name(),
0235                                                      m_sourceNode->opacity(),
0236                                                      clone);
0237 
0238                 m_targetNode->setCompositeOpId(m_compositeOp);
0239 
0240                 if (sourceLayer() && targetLayer()) {
0241                     targetLayer()->disableAlphaChannel(sourceLayer()->alphaChannelDisabled());
0242                 }
0243 
0244                 if (sourcePaintLayer() && targetPaintLayer()) {
0245                     targetPaintLayer()->setAlphaLocked(sourcePaintLayer()->alphaLocked());
0246                 }
0247             }
0248         }
0249 
0250         QSet<int> frames() {
0251             return m_frames;
0252         }
0253 
0254         KisNodeSP sourceNode() {
0255             return m_sourceNode;
0256         }
0257 
0258         KisLayerSP sourceLayer() {
0259             return qobject_cast<KisLayer*>(m_sourceNode.data());
0260         }
0261 
0262         KisNodeList sourceNodes() {
0263             KisNodeList list;
0264             list << m_sourceNode;
0265             return list;
0266         }
0267 
0268         KisPaintLayerSP sourcePaintLayer() {
0269             return qobject_cast<KisPaintLayer*>(m_sourceNode.data());
0270         }
0271 
0272         bool hasTargetNode() {
0273             return m_targetNode != nullptr;
0274         }
0275 
0276         KisNodeSP targetNode() {
0277             return m_targetNode;
0278         }
0279 
0280         KisLayerSP targetLayer() {
0281             return qobject_cast<KisLayer*>(m_targetNode.data());
0282         }
0283 
0284         KisPaintLayerSP targetPaintLayer() {
0285             return qobject_cast<KisPaintLayer*>(m_targetNode.data());
0286         }
0287 
0288 
0289         KisImageSP image() {
0290             return m_image;
0291         }
0292 
0293         KisPaintDeviceSP paintDevice() {
0294             return m_sourcePaintDevice;
0295         }
0296 
0297         KisNodeList toRemove() {
0298             KisNodeList lst;
0299             lst << m_sourceNode;
0300             return lst;
0301         }
0302 
0303         KisNodeSP insertionPutAfter() const {
0304             return m_insertionPutAfter;
0305         }
0306 
0307         KisNodeSP insertionParent() const {
0308             return m_insertionParent;
0309         }
0310 
0311         SwitchFrameCommand::SharedStorageSP storage;
0312 
0313     private:
0314         KisNodeSP m_sourceNode;
0315         KisNodeSP m_targetNode;
0316         KisImageWSP m_image;
0317         KisPaintDeviceSP m_sourcePaintDevice;
0318         QSet<int> m_frames;
0319         QString m_compositeOp;
0320         bool m_pinnedToTimeline;
0321 
0322         KisNodeSP m_insertionParent;
0323         KisNodeSP m_insertionPutAfter;
0324     };
0325 
0326     struct MergeMultipleInfo : public MergeDownInfoBase {
0327         MergeMultipleInfo(KisImageSP _image,
0328                           KisNodeList _mergedNodes)
0329             : MergeDownInfoBase(_image),
0330               mergedNodes(_mergedNodes)
0331         {
0332             foreach (KisNodeSP node, mergedNodes) {
0333                 frames |= fetchLayerFramesRecursive(node);
0334                 pinnedToTimeline |= node->isPinnedToTimeline();
0335 
0336                 const KisPaintLayer *paintLayer = qobject_cast<KisPaintLayer*>(node.data());
0337                 if (paintLayer) {
0338                     enableOnionSkins |= paintLayer->onionSkinEnabled();
0339                 }
0340             }
0341         }
0342 
0343         QScopedPointer<KisSurrogateUndoStore> ephemeralCommandsStore;
0344         KisNodeList mergedNodes;
0345         bool nodesCompositingVaries = false;
0346 
0347         KisNodeList allSrcNodes() override {
0348             return mergedNodes;
0349         }
0350     };
0351 
0352     typedef QSharedPointer<MergeDownInfoBase> MergeDownInfoBaseSP;
0353     typedef QSharedPointer<MergeDownInfo> MergeDownInfoSP;
0354     typedef QSharedPointer<MergeMultipleInfo> MergeMultipleInfoSP;
0355     typedef QSharedPointer<SplitAlphaToMaskInfo> SplitAlphaToMaskInfoSP;
0356     typedef QSharedPointer<ConvertToPaintLayerInfo> ConvertToPaintLayerInfoSP;
0357 
0358     struct FillSelectionMasks : public KUndo2Command {
0359         FillSelectionMasks(MergeDownInfoBaseSP info) : m_info(info) {}
0360 
0361         void redo() override {
0362             fetchSelectionMasks(m_info->allSrcNodes(), m_info->selectionMasks);
0363         }
0364 
0365     private:
0366         MergeDownInfoBaseSP m_info;
0367     };
0368 
0369     struct DisableColorizeKeyStrokes : public KisCommandUtils::AggregateCommand {
0370         DisableColorizeKeyStrokes(MergeDownInfoBaseSP info) : m_info(info) {}
0371 
0372         void populateChildCommands() override {
0373             Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
0374                 recursiveApplyNodes(node,
0375                                     [this] (KisNodeSP node) {
0376                                         if (dynamic_cast<KisColorizeMask*>(node.data()) &&
0377                                             KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::colorizeEditKeyStrokes, true).toBool()) {
0378 
0379                                             KisBaseNode::PropertyList props = node->sectionModelProperties();
0380                                             KisLayerPropertiesIcons::setNodeProperty(&props,
0381                                                                                      KisLayerPropertiesIcons::colorizeEditKeyStrokes,
0382                                                                                      false);
0383 
0384                                             addCommand(new KisNodePropertyListCommand(node, props));
0385                                         }
0386                                     });
0387             }
0388         }
0389 
0390     private:
0391         MergeDownInfoBaseSP m_info;
0392     };
0393 
0394     struct DisableOnionSkins : public KisCommandUtils::AggregateCommand {
0395         DisableOnionSkins(MergeDownInfoBaseSP info) : m_info(info) {}
0396 
0397         void populateChildCommands() override {
0398             Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
0399                 recursiveApplyNodes(node,
0400                                     [this] (KisNodeSP node) {
0401                                         if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::onionSkins, false).toBool()) {
0402 
0403                                             KisBaseNode::PropertyList props = node->sectionModelProperties();
0404                                             KisLayerPropertiesIcons::setNodeProperty(&props,
0405                                                                                      KisLayerPropertiesIcons::onionSkins,
0406                                                                                      false);
0407 
0408                                             addCommand(new KisNodePropertyListCommand(node, props));
0409                                         }
0410                                     });
0411             }
0412         }
0413 
0414     private:
0415         MergeDownInfoBaseSP m_info;
0416     };
0417 
0418     struct DisableExtraCompositing : public KisCommandUtils::AggregateCommand {
0419         DisableExtraCompositing(MergeMultipleInfoSP info) : m_info(info) {}
0420 
0421         void populateChildCommands() override {
0422             /**
0423              * We disable extra compositing only in case all the layers have
0424              * the same compositing properties, therefore, we can just sum them using
0425              * Normal blend mode
0426              */
0427             if (m_info->nodesCompositingVaries) return;
0428 
0429             // we should disable dirty requests on **redo only**, otherwise
0430             // the state of the layers will not be recovered on undo
0431             m_info->image->disableDirtyRequests();
0432 
0433             Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
0434                 if (node->compositeOpId() != COMPOSITE_OVER) {
0435                     addCommand(new KisNodeCompositeOpCommand(node, COMPOSITE_OVER));
0436                 }
0437 
0438                 if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::inheritAlpha, false).toBool()) {
0439 
0440                     KisBaseNode::PropertyList props = node->sectionModelProperties();
0441                     KisLayerPropertiesIcons::setNodeProperty(&props,
0442                                                              KisLayerPropertiesIcons::inheritAlpha,
0443                                                              false);
0444 
0445                     addCommand(new KisNodePropertyListCommand(node, props));
0446                 }
0447             }
0448 
0449             m_info->image->enableDirtyRequests();
0450         }
0451 
0452     private:
0453         MergeMultipleInfoSP m_info;
0454     };
0455 
0456     struct DisablePassThroughForHeadsOnly : public KisCommandUtils::AggregateCommand {
0457         DisablePassThroughForHeadsOnly(MergeDownInfoBaseSP info, bool skipIfDstIsGroup = false)
0458             : m_info(info),
0459               m_skipIfDstIsGroup(skipIfDstIsGroup)
0460         {
0461         }
0462 
0463         void populateChildCommands() override {
0464             if (m_skipIfDstIsGroup &&
0465                 m_info->dstLayer() &&
0466                 m_info->dstLayer()->inherits("KisGroupLayer")) {
0467 
0468                 return;
0469             }
0470 
0471 
0472             Q_FOREACH (KisNodeSP node, m_info->allSrcNodes()) {
0473                 if (KisLayerPropertiesIcons::nodeProperty(node, KisLayerPropertiesIcons::passThrough, false).toBool()) {
0474 
0475                     KisBaseNode::PropertyList props = node->sectionModelProperties();
0476                     KisLayerPropertiesIcons::setNodeProperty(&props,
0477                                                              KisLayerPropertiesIcons::passThrough,
0478                                                              false);
0479 
0480                     addCommand(new KisNodePropertyListCommand(node, props));
0481                 }
0482             }
0483         }
0484 
0485     private:
0486         MergeDownInfoBaseSP m_info;
0487         bool m_skipIfDstIsGroup;
0488     };
0489 
0490     struct RefreshHiddenAreas : public KisCommandUtils::AggregateCommand {
0491         struct refresh_entire_image_t {};
0492         static constexpr refresh_entire_image_t refresh_entire_image{};
0493 
0494         RefreshHiddenAreas(MergeDownInfoBaseSP info) : m_image(info->image), m_nodes(info->allSrcNodes()) {}
0495         RefreshHiddenAreas(MergeDownInfoBaseSP info, refresh_entire_image_t) : m_image(info->image), m_nodes(info->allSrcNodes()), m_extraUpdateRect(info->image->bounds()) {}
0496         RefreshHiddenAreas(KisImageSP image, KisNodeSP node) : m_image(image), m_nodes() {
0497             m_nodes << node;
0498         }
0499 
0500         void populateChildCommands() override {
0501             KisImageAnimationInterface *interface = m_image->animationInterface();
0502             const QRect preparedRect = !interface->externalFrameActive() ?
0503                 m_image->bounds() : QRect();
0504 
0505             foreach (KisNodeSP node, m_nodes) {
0506                 Private::refreshHiddenAreaAsync(m_image, node, preparedRect, m_extraUpdateRect);
0507             }
0508         }
0509 
0510     private:
0511         KisImageWSP m_image;
0512         KisNodeList m_nodes;
0513         QRect m_extraUpdateRect;
0514     };
0515 
0516     struct RefreshDelayedUpdateLayers : public KUndo2Command {
0517         RefreshDelayedUpdateLayers(MergeDownInfoBaseSP info)
0518             : m_nodes(info->allSrcNodes()) {}
0519 
0520         RefreshDelayedUpdateLayers(KisNodeList nodes){
0521             m_nodes << nodes;
0522         }
0523 
0524         void redo() override {
0525             if (m_info) {
0526                 m_nodes << m_info->allSrcNodes();
0527             }
0528 
0529             foreach (KisNodeSP node, m_nodes) {
0530                 forceAllDelayedNodesUpdate(node);
0531             }
0532         }
0533 
0534     private:
0535         KisNodeList m_nodes;
0536         MergeDownInfoBaseSP m_info;
0537     };
0538 
0539     struct KeepMergedNodesSelected : public KisCommandUtils::AggregateCommand {
0540         KeepMergedNodesSelected(MergeDownInfoSP info, bool finalizing)
0541             : m_singleInfo(info),
0542               m_finalizing(finalizing) {}
0543 
0544         KeepMergedNodesSelected(MergeMultipleInfoSP info, KisNodeSP putAfter, bool finalizing)
0545             : m_multipleInfo(info),
0546               m_finalizing(finalizing),
0547               m_putAfter(putAfter) {}
0548 
0549         void populateChildCommands() override {
0550             KisNodeSP prevNode;
0551             KisNodeSP nextNode;
0552             KisNodeList prevSelection;
0553             KisNodeList nextSelection;
0554             KisImageSP image;
0555 
0556             if (m_singleInfo) {
0557                 prevNode = m_singleInfo->currLayer;
0558                 nextNode = m_singleInfo->dstNode;
0559                 image = m_singleInfo->image;
0560             } else if (m_multipleInfo) {
0561                 prevNode = m_putAfter;
0562                 nextNode = m_multipleInfo->dstNode;
0563                 prevSelection = m_multipleInfo->allSrcNodes();
0564                 image = m_multipleInfo->image;
0565             }
0566 
0567             if (!m_finalizing) {
0568                 addCommand(new KeepNodesSelectedCommand(prevSelection, KisNodeList(),
0569                                                         prevNode, KisNodeSP(),
0570                                                         image, false));
0571             } else {
0572                 addCommand(new KeepNodesSelectedCommand(KisNodeList(), nextSelection,
0573                                                         KisNodeSP(), nextNode,
0574                                                         image, true));
0575             }
0576         }
0577 
0578     private:
0579         MergeDownInfoSP m_singleInfo;
0580         MergeMultipleInfoSP m_multipleInfo;
0581         bool m_finalizing;
0582         KisNodeSP m_putAfter;
0583     };
0584 
0585     struct CreateMergedLayer : public KisCommandUtils::AggregateCommand {
0586         CreateMergedLayer(MergeDownInfoSP info) : m_info(info) {}
0587 
0588         void populateChildCommands() override {
0589             // actual merging done by KisLayer::createMergedLayer (or specialized descendant)
0590             m_info->dstNode = m_info->currLayer->createMergedLayerTemplate(m_info->prevLayer);
0591 
0592             if (m_info->frames.size() > 0) {
0593                 m_info->dstNode->enableAnimation();
0594                 m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true);
0595             }
0596 
0597             m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline);
0598             m_info->dstNode->setColorLabelIndex(m_info->allSrcNodes().first()->colorLabelIndex());
0599 
0600             KisPaintLayer *dstPaintLayer = qobject_cast<KisPaintLayer*>(m_info->dstNode.data());
0601             if (dstPaintLayer) {
0602                 dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins);
0603             }
0604         }
0605 
0606     private:
0607         MergeDownInfoSP m_info;
0608     };
0609 
0610     struct CreateMergedLayerMultiple : public KisCommandUtils::AggregateCommand {
0611         CreateMergedLayerMultiple(MergeMultipleInfoSP info, const QString name = QString() )
0612             : m_info(info),
0613               m_name(name) {}
0614 
0615         void populateChildCommands() override {
0616             QString mergedLayerName;
0617             if (m_name.isEmpty()){
0618                 const QString mergedLayerSuffix = i18n("Merged");
0619                 mergedLayerName = m_info->mergedNodes.first()->name();
0620 
0621                 if (KisImageConfig(true).renameMergedLayers() && !mergedLayerName.endsWith(mergedLayerSuffix)) {
0622                     mergedLayerName = QString("%1 %2")
0623                         .arg(mergedLayerName).arg(mergedLayerSuffix);
0624                 }
0625             } else {
0626                 mergedLayerName = m_name;
0627             }
0628 
0629             KisPaintLayer *dstPaintLayer = new KisPaintLayer(m_info->image, mergedLayerName, OPACITY_OPAQUE_U8);
0630             m_info->dstNode = dstPaintLayer;
0631 
0632             if (m_info->frames.size() > 0) {
0633                 m_info->dstNode->enableAnimation();
0634                 m_info->dstNode->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true);
0635             }
0636 
0637 
0638             auto channelFlagsLazy = [](KisNodeSP node) {
0639                 KisLayer *layer = dynamic_cast<KisLayer*>(node.data());
0640                 return layer ? layer->channelFlags() : QBitArray();
0641             };
0642 
0643             QString compositeOpId;
0644             QBitArray channelFlags;
0645             bool compositionVaries = false;
0646             bool isFirstCycle = true;
0647 
0648             foreach (KisNodeSP node, m_info->allSrcNodes()) {
0649                 if (isFirstCycle) {
0650                     compositeOpId = node->compositeOpId();
0651                     channelFlags = channelFlagsLazy(node);
0652                     isFirstCycle = false;
0653                 } else if (compositeOpId != node->compositeOpId() ||
0654                            channelFlags != channelFlagsLazy(node)) {
0655                     compositionVaries = true;
0656                     break;
0657                 }
0658 
0659                 KisLayerSP layer = qobject_cast<KisLayer*>(node.data());
0660                 if (layer && layer->layerStyle()) {
0661                     compositionVaries = true;
0662                     break;
0663                 }
0664             }
0665 
0666             if (!compositionVaries) {
0667                 if (!compositeOpId.isEmpty()) {
0668                     m_info->dstNode->setCompositeOpId(compositeOpId);
0669                 }
0670                 if (m_info->dstLayer() && !channelFlags.isEmpty()) {
0671                     m_info->dstLayer()->setChannelFlags(channelFlags);
0672                 }
0673             }
0674 
0675             m_info->nodesCompositingVaries = compositionVaries;
0676 
0677             m_info->dstNode->setPinnedToTimeline(m_info->pinnedToTimeline);
0678             m_info->dstNode->setColorLabelIndex(m_info->allSrcNodes().first()->colorLabelIndex());
0679 
0680             dstPaintLayer->setOnionSkinEnabled(m_info->enableOnionSkins);
0681         }
0682 
0683     private:
0684         MergeMultipleInfoSP m_info;
0685         QString m_name;
0686     };
0687 
0688     struct MergeLayers : public KisCommandUtils::AggregateCommand {
0689         MergeLayers(MergeDownInfoSP info, bool skipMergingSourceLayer)
0690             : m_info(info), m_skipMergingSourceLayer(skipMergingSourceLayer) {}
0691 
0692         void populateChildCommands() override {
0693             // actual merging done by KisLayer::createMergedLayer (or specialized descendant)
0694             m_info->currLayer->fillMergedLayerTemplate(m_info->dstLayer(), m_info->prevLayer, m_skipMergingSourceLayer);
0695         }
0696 
0697     private:
0698         MergeDownInfoSP m_info;
0699         bool m_skipMergingSourceLayer {false};
0700     };
0701 
0702     struct MergeLayersMultiple : public KisCommandUtils::AggregateCommand {
0703         MergeLayersMultiple(MergeMultipleInfoSP info) : m_info(info) {}
0704 
0705         void populateChildCommands() override {
0706             KisPainter gc(m_info->dstNode->paintDevice());
0707 
0708             foreach (KisNodeSP node, m_info->allSrcNodes()) {
0709                 QRect rc = node->exactBounds() | m_info->image->bounds();
0710                 node->projectionPlane()->apply(&gc, rc);
0711             }
0712         }
0713 
0714     private:
0715         MergeMultipleInfoSP m_info;
0716     };
0717 
0718     struct MergeMetaData : public KUndo2Command {
0719         MergeMetaData(MergeDownInfoSP info, const KisMetaData::MergeStrategy* strategy)
0720             : m_info(info),
0721               m_strategy(strategy) {}
0722 
0723         void redo() override {
0724             QRect layerProjectionExtent = m_info->currLayer->projection()->extent();
0725             QRect prevLayerProjectionExtent = m_info->prevLayer->projection()->extent();
0726             int prevLayerArea = prevLayerProjectionExtent.width() * prevLayerProjectionExtent.height();
0727             int layerArea = layerProjectionExtent.width() * layerProjectionExtent.height();
0728 
0729             QList<double> scores;
0730             double norm = qMax(prevLayerArea, layerArea);
0731             scores.append(prevLayerArea / norm);
0732             scores.append(layerArea / norm);
0733 
0734             QList<const KisMetaData::Store*> srcs;
0735             srcs.append(m_info->prevLayer->metaData());
0736             srcs.append(m_info->currLayer->metaData());
0737             m_strategy->merge(m_info->dstLayer()->metaData(), srcs, scores);
0738         }
0739 
0740     private:
0741         MergeDownInfoSP m_info;
0742         const KisMetaData::MergeStrategy *m_strategy;
0743     };
0744 
0745     struct InitSplitAlphaSelectionMask : public KisCommandUtils::AggregateCommand  {
0746         InitSplitAlphaSelectionMask(SplitAlphaToMaskInfoSP info)
0747             : m_info(info) {}
0748 
0749         void populateChildCommands() override {
0750             m_info->getMask()->initSelection(m_info->getLayer());
0751         }
0752 
0753     private:
0754         SplitAlphaToMaskInfoSP m_info;
0755     };
0756 
0757     struct SplitAlphaCommand : public KUndo2Command  {
0758         SplitAlphaCommand(SplitAlphaToMaskInfoSP info)
0759             : m_info(info) {
0760             m_cached = new KisPaintDevice(*m_info->node->paintDevice(), KritaUtils::CopyAllFrames);
0761         }
0762 
0763         void redo() override {
0764             KisPaintDeviceSP srcDevice = m_info->node->paintDevice();
0765             const KoColorSpace *srcCS = srcDevice->colorSpace();
0766             const QRect processRect =
0767                     srcDevice->exactBounds() |
0768                     srcDevice->defaultBounds()->bounds();
0769 
0770             KisSequentialIterator srcIt(srcDevice, processRect);
0771             KisSequentialIterator dstIt(m_info->getMaskDevice(), processRect);
0772 
0773             while (srcIt.nextPixel() && dstIt.nextPixel()) {
0774                 quint8 *srcPtr = srcIt.rawData();
0775                 quint8 *alpha8Ptr = dstIt.rawData();
0776 
0777                 *alpha8Ptr = srcCS->opacityU8(srcPtr);
0778                 srcCS->setOpacity(srcPtr, OPACITY_OPAQUE_U8, 1);
0779             }
0780         }
0781 
0782         void undo() override {
0783             KisPaintDeviceSP srcDevice = m_info->node->paintDevice();
0784 
0785             if (srcDevice->framesInterface()) { //Swap contents of all frames to reflect the pre-operation state.
0786                 KisPaintDeviceSP tempPD = new KisPaintDevice(*m_cached, KritaUtils::CopySnapshot);
0787                 Q_FOREACH(const int& frame, srcDevice->framesInterface()->frames() ) {
0788                     if (m_cached->framesInterface()->frames().contains(frame)) {
0789                         m_cached->framesInterface()->writeFrameToDevice(frame, tempPD);
0790                         srcDevice->framesInterface()->uploadFrame(frame, tempPD);
0791                     }
0792                 }
0793             } else {
0794                 const QRect processRect =
0795                         srcDevice->exactBounds() |
0796                         srcDevice->defaultBounds()->bounds();
0797 
0798                 const KoColorSpace *srcCS = srcDevice->colorSpace();
0799                 KisSequentialIterator srcIt(m_cached, processRect);
0800                 KisSequentialIterator dstIt(srcDevice, processRect);
0801 
0802                 while (srcIt.nextPixel() && dstIt.nextPixel()) {
0803                     quint8 *srcPtr = srcIt.rawData();
0804                     quint8 *dstPtr = dstIt.rawData();
0805                     srcCS->setOpacity(dstPtr, srcCS->opacityU8(srcPtr), 1);
0806                 }
0807             }
0808         }
0809 
0810     private:
0811         SplitAlphaToMaskInfoSP m_info;
0812         KisPaintDeviceSP m_cached;
0813     };
0814 
0815     struct UploadProjectionToFrameCommand : public KisCommandUtils::AggregateCommand {
0816         UploadProjectionToFrameCommand(KisNodeSP src, KisNodeSP target, int frame)
0817             : m_source(src)
0818             , m_target(target)
0819             , m_frame(frame)
0820         {}
0821 
0822         void populateChildCommands() override {
0823             KisRasterKeyframeChannel* channel = dynamic_cast<KisRasterKeyframeChannel*>(m_target->getKeyframeChannel(KisKeyframeChannel::Raster.id()));
0824             if (!channel)
0825                 return;
0826 
0827 
0828             KisPaintDeviceSP clone = new KisPaintDevice(*m_source->projection());
0829             KisRasterKeyframeSP key = channel->keyframeAt<KisRasterKeyframe>(m_frame);
0830             m_target->paintDevice()->framesInterface()->uploadFrame(key->frameID(), clone);
0831         }
0832 
0833     private:
0834         KisNodeSP m_source;
0835         KisNodeSP m_target;
0836         int m_frame;
0837     };
0838 
0839     KeepNodesSelectedCommand::KeepNodesSelectedCommand(const KisNodeList &selectedBefore,
0840                                                        const KisNodeList &selectedAfter,
0841                                                        KisNodeSP activeBefore,
0842                                                        KisNodeSP activeAfter,
0843                                                        KisImageSP image,
0844                                                        bool finalize, KUndo2Command *parent)
0845         : FlipFlopCommand(finalize, parent),
0846           m_selectedBefore(selectedBefore),
0847           m_selectedAfter(selectedAfter),
0848           m_activeBefore(activeBefore),
0849           m_activeAfter(activeAfter),
0850           m_image(image)
0851     {
0852     }
0853 
0854     void KeepNodesSelectedCommand::partB() {
0855         KisImageSignalType type;
0856         if (getState() == State::FINALIZING) {
0857             type = ComplexNodeReselectionSignal(m_activeAfter, m_selectedAfter);
0858         } else {
0859             type = ComplexNodeReselectionSignal(m_activeBefore, m_selectedBefore);
0860         }
0861         m_image->signalRouter()->emitNotification(type);
0862     }
0863 
0864     SelectGlobalSelectionMask::SelectGlobalSelectionMask(KisImageSP image)
0865         : m_image(image)
0866     {
0867     }
0868 
0869     SelectGlobalSelectionMask::~SelectGlobalSelectionMask()
0870     {
0871     }
0872 
0873     void SelectGlobalSelectionMask::redo() {
0874 
0875         KisImageSignalType type =
0876                 ComplexNodeReselectionSignal(m_image->rootLayer()->selectionMask(), KisNodeList());
0877         m_image->signalRouter()->emitNotification(type);
0878 
0879     }
0880 
0881     RemoveNodeHelper::~RemoveNodeHelper()
0882     {
0883     }
0884 
0885     /**
0886      * The removal of two nodes in one go may be a bit tricky, because one
0887      * of them may be the clone of another. If we remove the source of a
0888      * clone layer, it will reincarnate into a paint layer. In this case
0889      * the pointer to the second layer will be lost.
0890      *
0891      * That's why we need to care about the order of the nodes removal:
0892      * the clone --- first, the source --- last.
0893      */
0894     void RemoveNodeHelper::safeRemoveMultipleNodes(KisNodeList nodes, KisImageSP image) {
0895         const bool lastLayer = scanForLastLayer(image, nodes);
0896 
0897         auto isNodeWeird = [] (KisNodeSP node) {
0898             const bool normalCompositeMode = node->compositeOpId() == COMPOSITE_OVER;
0899 
0900             KisLayer *layer = dynamic_cast<KisLayer*>(node.data());
0901             const bool hasInheritAlpha = layer && layer->alphaChannelDisabled();
0902             return !normalCompositeMode && !hasInheritAlpha;
0903         };
0904 
0905         while (!nodes.isEmpty()) {
0906             KisNodeList::iterator it = nodes.begin();
0907 
0908             while (it != nodes.end()) {
0909                 if (!checkIsSourceForClone(*it, nodes)) {
0910                     KisNodeSP node = *it;
0911 
0912                     addCommandImpl(new KisImageLayerRemoveCommand(image, node, !isNodeWeird(node), true));
0913                     it = nodes.erase(it);
0914                 } else {
0915                     ++it;
0916                 }
0917             }
0918         }
0919 
0920         if (lastLayer) {
0921             KisLayerSP newLayer = new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, image->colorSpace());
0922             addCommandImpl(new KisImageLayerAddCommand(image, newLayer,
0923                                                        image->root(),
0924                                                        KisNodeSP(),
0925                                                        false, false));
0926         }
0927     }
0928 
0929     bool RemoveNodeHelper::checkIsSourceForClone(KisNodeSP src, const KisNodeList &nodes) {
0930         foreach (KisNodeSP node, nodes) {
0931             if (node == src) continue;
0932 
0933             KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
0934 
0935             if (clone && KisNodeSP(clone->copyFrom()) == src) {
0936                 return true;
0937             }
0938         }
0939 
0940         return false;
0941     }
0942 
0943     bool RemoveNodeHelper::scanForLastLayer(KisImageWSP image, KisNodeList nodesToRemove) {
0944         bool removeLayers = false;
0945         Q_FOREACH(KisNodeSP nodeToRemove, nodesToRemove) {
0946             if (qobject_cast<KisLayer*>(nodeToRemove.data())) {
0947                 removeLayers = true;
0948                 break;
0949             }
0950         }
0951         if (!removeLayers) return false;
0952 
0953         bool lastLayer = true;
0954         KisNodeSP node = image->root()->firstChild();
0955         while (node) {
0956             if (!nodesToRemove.contains(node) &&
0957                 qobject_cast<KisLayer*>(node.data()) &&
0958                 !node->isFakeNode()) {
0959 
0960                 lastLayer = false;
0961                 break;
0962             }
0963             node = node->nextSibling();
0964         }
0965 
0966         return lastLayer;
0967     }
0968 
0969     SimpleRemoveLayers::SimpleRemoveLayers(const KisNodeList &nodes,
0970                                            KisImageSP image)
0971         : m_nodes(nodes),
0972           m_image(image)
0973     {
0974     }
0975 
0976     void SimpleRemoveLayers::populateChildCommands() {
0977         if (m_nodes.isEmpty()) return;
0978         safeRemoveMultipleNodes(m_nodes, m_image);
0979     }
0980 
0981     void SimpleRemoveLayers::addCommandImpl(KUndo2Command *cmd) {
0982         addCommand(cmd);
0983     }
0984 
0985     struct InsertNode : public KisCommandUtils::AggregateCommand {
0986         InsertNode(MergeDownInfoBaseSP info, KisNodeSP putAfter)
0987             : m_info(info), m_putAfter(putAfter) {}
0988 
0989         void populateChildCommands() override {
0990             addCommand(new KisImageLayerAddCommand(m_info->image,
0991                                                            m_info->dstNode,
0992                                                            m_putAfter->parent(),
0993                                                            m_putAfter,
0994                                                            true, false));
0995 
0996         }
0997 
0998     private:
0999         virtual void addCommandImpl(KUndo2Command *cmd) {
1000             addCommand(cmd);
1001         }
1002 
1003         MergeDownInfoBaseSP m_info;
1004         KisNodeSP m_putAfter;
1005     };
1006 
1007     struct SimpleAddNode : public KisCommandUtils::AggregateCommand {
1008         SimpleAddNode(KisImageSP image, KisNodeSP toAdd, KisNodeSP parent = 0, KisNodeSP putAfter = 0)
1009             : m_image(image)
1010             , m_toAdd(toAdd)
1011             , m_parent(parent)
1012             , m_putAfter(putAfter)
1013         {
1014             while (m_parent && !m_parent->allowAsChild(m_toAdd)) {
1015                 m_putAfter = m_putAfter ? m_putAfter->parent() : m_parent;
1016                 m_parent = m_putAfter ? m_putAfter->parent() : 0;
1017             }
1018 
1019             if (!m_parent) {
1020                 m_parent = m_image->root();
1021             }
1022         }
1023 
1024 
1025         void populateChildCommands() override {
1026             addCommand(new KisImageLayerAddCommand(m_image,
1027                                                        m_toAdd,
1028                                                        m_parent,
1029                                                        m_putAfter,
1030                                                        true, false));
1031         }
1032 
1033     private:
1034         virtual void addCommandImpl(KUndo2Command *cmd) {
1035             addCommand(cmd);
1036         }
1037 
1038         KisImageWSP m_image;
1039         KisNodeSP m_toAdd;
1040         KisNodeSP m_parent;
1041         KisNodeSP m_putAfter;
1042 
1043     };
1044 
1045 
1046     void splitNonRemovableNodes(KisNodeList &nodesToRemove, KisNodeList &_nodesToHide)
1047     {
1048         QSet<KisNodeSP> nodesToHide;
1049         QSet<KisNodeSP> extraNodesToRemove;
1050 
1051         for (auto it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) {
1052             KisNodeSP root = *it;
1053             KIS_SAFE_ASSERT_RECOVER_NOOP(root->visible());
1054 
1055             if (!root->isEditable(false)) {
1056                 nodesToHide.insert(root);
1057             } else {
1058                 bool rootNeedsCarefulRemoval = false;
1059 
1060                 recursiveApplyNodes(root,
1061                                     [root, &nodesToHide, &rootNeedsCarefulRemoval] (KisNodeSP node) {
1062                                         if (!node->isEditable(false)) {
1063                                             while (node != root) {
1064                                                 nodesToHide.insert(node);
1065                                                 node = node->parent();
1066                                                 KIS_SAFE_ASSERT_RECOVER_BREAK(node);
1067                                             }
1068                                             nodesToHide.insert(root);
1069                                             rootNeedsCarefulRemoval = true;
1070                                         }
1071                                     });
1072 
1073                 if (rootNeedsCarefulRemoval) {
1074                     recursiveApplyNodes(root,
1075                                         [&extraNodesToRemove] (KisNodeSP node) {
1076                                             extraNodesToRemove.insert(node);
1077                                         });
1078                 }
1079             }
1080         }
1081 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1082         nodesToRemove += KisNodeList(extraNodesToRemove.begin(), extraNodesToRemove.end());
1083 #else
1084         nodesToRemove += extraNodesToRemove.toList();
1085 #endif
1086         KritaUtils::filterContainer<KisNodeList>(nodesToRemove,
1087                                                  [nodesToHide](KisNodeSP node) {
1088                                                      return !nodesToHide.contains(node);
1089                                                  });
1090 #if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
1091         _nodesToHide = KisNodeList(nodesToHide.begin(), nodesToHide.end());
1092 #else
1093         _nodesToHide = nodesToHide.toList();
1094 #endif
1095     }
1096 
1097     struct CleanUpNodes : private RemoveNodeHelper, public KisCommandUtils::AggregateCommand {
1098         CleanUpNodes(MergeDownInfoBaseSP info, KisNodeSP putAfter)
1099             : m_info(info), m_putAfter(putAfter) {}
1100 
1101         static void findPerfectParent(KisNodeList nodesToDelete, KisNodeSP &putAfter, KisNodeSP &parent) {
1102             if (!putAfter) {
1103                 putAfter = nodesToDelete.last();
1104             }
1105 
1106             // Add the new merged node on top of the active node
1107             // -- checking all parents if they are included in nodesToDelete
1108             // Not every descendant is included in nodesToDelete even if in fact
1109             //   they are going to be deleted, so we need to check it.
1110             // If we consider the path from root to the putAfter node,
1111             //    if there are any nodes marked for deletion, any node afterwards
1112             //    is going to be deleted, too.
1113             //   example:      root . . . . . ! ! . . ! ! ! ! . . . . putAfter
1114             //   it should be: root . . . . . ! ! ! ! ! ! ! ! ! ! ! ! !putAfter
1115             //   and here:     root . . . . X ! ! . . ! ! ! ! . . . . putAfter
1116             //   you can see which node is "the perfect ancestor"
1117             //   (marked X; called "parent" in the function arguments).
1118             //   and here:     root . . . . . O ! . . ! ! ! ! . . . . putAfter
1119             //   you can see which node is "the topmost deleted ancestor" (marked 'O')
1120 
1121             KisNodeSP node = putAfter->parent();
1122             bool foundDeletedAncestor = false;
1123             KisNodeSP topmostAncestorToDelete = nullptr;
1124 
1125             while (node) {
1126 
1127                 if (nodesToDelete.contains(node)
1128                         && !nodesToDelete.contains(node->parent())) {
1129                     foundDeletedAncestor = true;
1130                     topmostAncestorToDelete = node;
1131                     // Here node is to be deleted and its parent is not,
1132                     // so its parent is the one of the first not deleted (="perfect") ancestors.
1133                     // We need the one that is closest to the top (root)
1134                 }
1135 
1136                 node = node->parent();
1137             }
1138 
1139             if (foundDeletedAncestor) {
1140                 parent = topmostAncestorToDelete->parent();
1141                 putAfter = topmostAncestorToDelete;
1142             }
1143             else {
1144                 parent = putAfter->parent(); // putAfter (and none of its ancestors) is to be deleted, so its parent is the first not deleted ancestor
1145             }
1146 
1147         }
1148 
1149         void populateChildCommands() override {
1150             KisNodeList nodesToDelete = m_info->allSrcNodes();
1151 
1152             KisNodeSP parent;
1153             findPerfectParent(nodesToDelete, m_putAfter, parent);
1154 
1155             if (!parent) {
1156                 KisNodeSP oldRoot = m_info->image->root();
1157                 KisNodeSP newRoot(new KisGroupLayer(m_info->image, "root", OPACITY_OPAQUE_U8));
1158 
1159                 // copy all fake nodes into the new image
1160                 KisLayerUtils::recursiveApplyNodes(oldRoot, [this, oldRoot, newRoot] (KisNodeSP node) {
1161                     if (node->isFakeNode() && node->parent() == oldRoot) {
1162                         addCommand(new KisImageLayerAddCommand(m_info->image,
1163                                                                node->clone(),
1164                                                                newRoot,
1165                                                                KisNodeSP(),
1166                                                                false, false));
1167 
1168                     }
1169                 });
1170 
1171                 addCommand(new KisImageLayerAddCommand(m_info->image,
1172                                                        m_info->dstNode,
1173                                                        newRoot,
1174                                                        KisNodeSP(),
1175                                                        true, false));
1176                 addCommand(new KisImageChangeLayersCommand(m_info->image, oldRoot, newRoot));
1177 
1178             }
1179             else {
1180                 addCommand(new KisImageLayerAddCommand(m_info->image,
1181                                                        m_info->dstNode,
1182                                                        parent,
1183                                                        m_putAfter,
1184                                                        true, false));
1185 
1186 
1187                 /**
1188                  * We can merge selection masks, in this case dstLayer is not defined!
1189                  */
1190                 if (m_info->dstLayer()) {
1191                     reparentSelectionMasks(m_info->image,
1192                                            m_info->dstLayer(),
1193                                            m_info->selectionMasks);
1194                 }
1195 
1196                 KisNodeList safeNodesToDelete = m_info->allSrcNodes();
1197                 KisNodeList safeNodesToHide;
1198 
1199                 splitNonRemovableNodes(safeNodesToDelete, safeNodesToHide);
1200 
1201                 Q_FOREACH(KisNodeSP node, safeNodesToHide) {
1202                     addCommand(new KisImageChangeVisibilityCommand(false, node));
1203                 }
1204 
1205                 safeRemoveMultipleNodes(safeNodesToDelete, m_info->image);
1206             }
1207 
1208 
1209         }
1210 
1211     private:
1212         void addCommandImpl(KUndo2Command *cmd) override {
1213             addCommand(cmd);
1214         }
1215 
1216         void reparentSelectionMasks(KisImageSP image,
1217                                     KisLayerSP newLayer,
1218                                     const QVector<KisSelectionMaskSP> &selectionMasks) {
1219 
1220             KIS_SAFE_ASSERT_RECOVER_RETURN(newLayer);
1221 
1222             foreach (KisSelectionMaskSP mask, selectionMasks) {
1223                 addCommand(new KisImageLayerMoveCommand(image, mask, newLayer, newLayer->lastChild()));
1224                 addCommand(new KisActivateSelectionMaskCommand(mask, false));
1225             }
1226         }
1227     private:
1228         MergeDownInfoBaseSP m_info;
1229         KisNodeSP m_putAfter;
1230     };
1231 
1232     SwitchFrameCommand::SharedStorage::~SharedStorage() {
1233     }
1234 
1235     SwitchFrameCommand::SwitchFrameCommand(KisImageSP image, int time, bool finalize, SharedStorageSP storage)
1236         : FlipFlopCommand(finalize),
1237           m_image(image),
1238           m_newTime(time),
1239           m_storage(storage) {}
1240 
1241     SwitchFrameCommand::~SwitchFrameCommand() {}
1242 
1243     void SwitchFrameCommand::partA() {
1244         KisImageAnimationInterface *interface = m_image->animationInterface();
1245         const int currentTime = interface->currentTime();
1246         if (currentTime == m_newTime) {
1247             m_storage->value = m_newTime;
1248             return;
1249         }
1250 
1251         interface->image()->disableUIUpdates();
1252         interface->saveAndResetCurrentTime(m_newTime, &m_storage->value);
1253     }
1254 
1255     void SwitchFrameCommand::partB() {
1256         KisImageAnimationInterface *interface = m_image->animationInterface();
1257         const int currentTime = interface->currentTime();
1258         if (currentTime == m_storage->value) {
1259             return;
1260         }
1261 
1262         interface->restoreCurrentTime(&m_storage->value);
1263         interface->image()->enableUIUpdates();
1264     }
1265 
1266     struct AddNewFrame : public KisCommandUtils::AggregateCommand {
1267         AddNewFrame(KisNodeSP node, int frame) : m_node(node), m_frame(frame) {}
1268         AddNewFrame(KisNodeSP node, int frame, KisNodeList sampleNodes) : m_node(node), m_frame(frame), m_sampledNodes(sampleNodes) {}
1269         AddNewFrame(KisNodeSP node, int frame, KisNodeSP source) : m_node(node), m_frame(frame) { m_sampledNodes << source; }
1270         AddNewFrame(MergeDownInfoBaseSP info, int frame) : m_frame(frame), m_sampledNodes(info->allSrcNodes()), m_mergeInfo(info) {}
1271 
1272         void populateChildCommands() override {
1273             KUndo2Command *cmd = new KUndo2Command;
1274             KisNodeSP node = m_node ? m_node : m_mergeInfo->dstNode;
1275             KisKeyframeChannel *channel = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true);
1276             channel->addKeyframe(m_frame, cmd);
1277 
1278             if (m_sampledNodes.count() > 0) {
1279                 applyKeyframeColorLabel(channel->keyframeAt(m_frame), m_sampledNodes);
1280             }
1281 
1282             addCommand(cmd);
1283         }
1284 
1285         void applyKeyframeColorLabel(KisKeyframeSP dstKeyframe, KisNodeList srcNodes) {
1286             Q_FOREACH(KisNodeSP srcNode, srcNodes) {
1287                 Q_FOREACH(KisKeyframeChannel *channel, srcNode->keyframeChannels().values()) {
1288                     KisKeyframeSP keyframe = channel->keyframeAt(m_frame);
1289                     if (!keyframe.isNull() && keyframe->colorLabel() != 0) {
1290                         dstKeyframe->setColorLabel(keyframe->colorLabel());
1291                         return;
1292                     }
1293                 }
1294             }
1295 
1296             dstKeyframe->setColorLabel(0);
1297         }
1298 
1299     private:
1300         KisNodeSP m_node;
1301         int m_frame;
1302         KisNodeList m_sampledNodes;
1303         MergeDownInfoBaseSP m_mergeInfo;
1304     };
1305 
1306     QSet<int> fetchLayerFrames(KisNodeSP node) {
1307         QSet<int> frames;
1308         Q_FOREACH(KisKeyframeChannel *channel, node->keyframeChannels()) {
1309             if (!channel) {
1310                 continue;
1311             }
1312 
1313             KisRasterKeyframeChannel *rasterChan = dynamic_cast<KisRasterKeyframeChannel*>(channel);
1314             if (rasterChan) {
1315                 frames.unite(rasterChan->allKeyframeTimes());
1316                 continue;
1317             }
1318 
1319             KisScalarKeyframeChannel *scalarChan = dynamic_cast<KisScalarKeyframeChannel*>(channel);
1320             if (scalarChan) {
1321                 const int initialKeyframe = scalarChan->firstKeyframeTime();
1322 
1323                 if (initialKeyframe == -1) {
1324                     continue;
1325                 }
1326 
1327                 const int lastKeyframe = scalarChan->lastKeyframeTime();
1328                 KisTimeSpan currentSpan = scalarChan->identicalFrames(initialKeyframe);
1329                 while (!currentSpan.isInfinite() && currentSpan.isValid() && currentSpan.start() < lastKeyframe) {
1330                     frames.insert(currentSpan.start());
1331                     currentSpan = scalarChan->identicalFrames(currentSpan.end() + 1);
1332                 }
1333 
1334                 frames.insert(lastKeyframe);
1335             }
1336 
1337         }
1338 
1339         return frames;
1340     }
1341 
1342     QSet<int> fetchLayerFramesRecursive(KisNodeSP rootNode) {
1343         if (!rootNode->visible()) return QSet<int>();
1344 
1345         QSet<int> frames = fetchLayerFrames(rootNode);
1346 
1347         KisNodeSP node = rootNode->firstChild();
1348         while(node) {
1349             frames |= fetchLayerFramesRecursive(node);
1350             node = node->nextSibling();
1351         }
1352 
1353         return frames;
1354     }
1355 
1356     void updateFrameJobs(FrameJobs *jobs, KisNodeSP node) {
1357         QSet<int> frames = fetchLayerFrames(node);
1358         frames = fetchUniqueFrameTimes(node, frames, false);
1359 
1360         if (frames.isEmpty()) {
1361             (*jobs)[0].insert(node);
1362         } else {
1363             foreach (int frame, frames) {
1364                 (*jobs)[frame].insert(node);
1365             }
1366         }
1367     }
1368 
1369     void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode) {
1370         updateFrameJobs(jobs, rootNode);
1371 
1372         KisNodeSP node = rootNode->firstChild();
1373         while(node) {
1374             updateFrameJobsRecursive(jobs, node);
1375             node = node->nextSibling();
1376         }
1377     }
1378 
1379     /**
1380      * \see a comment in mergeMultipleLayersImpl()
1381      */
1382     void mergeDown(KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy* strategy)
1383     {
1384         if (!layer->prevSibling()) return;
1385 
1386         // XXX: this breaks if we allow free mixing of masks and layers
1387         KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
1388         if (!prevLayer) return;
1389 
1390         if (!layer->visible() && !prevLayer->visible()) {
1391             return;
1392         }
1393 
1394         KisImageSignalVector emitSignals;
1395         KisProcessingApplicator applicator(image, 0,
1396                                            KisProcessingApplicator::NONE,
1397                                            emitSignals,
1398                                            kundo2_i18n("Merge Down"));
1399 
1400         if (layer->visible() && prevLayer->visible()) {
1401             MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer));
1402 
1403             // disable key strokes on all colorize masks, all onion skins on
1404             // paint layers and wait until update is finished with a barrier
1405             applicator.applyCommand(new DisableColorizeKeyStrokes(info));
1406             applicator.applyCommand(new DisableOnionSkins(info));
1407             applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1408 
1409             applicator.applyCommand(new KeepMergedNodesSelected(info, false));
1410             applicator.applyCommand(new FillSelectionMasks(info));
1411             applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER);
1412 
1413             // NOTE: shape layer may have emitted spontaneous jobs during layer creation,
1414             //       wait for them to complete!
1415             applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1416             applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1417 
1418             // in two-layer mode we disable pass through only when the destination layer
1419             // is not a group layer
1420             applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true));
1421             applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1422 
1423             if (info->frames.size() > 0) {
1424                 /**
1425                  * Save the original time before we start switching is with
1426                  * asynchronous SwitchFrameCommand.
1427                  */
1428                 const int currentTimeOnStart = info->image->animationInterface()->currentTime();
1429 
1430                 foreach (int frame, info->frames) {
1431                     applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1432 
1433                     applicator.applyCommand(new AddNewFrame(info, frame));
1434                     /**
1435                      * When switching frames we need to update the entire image, not
1436                      * only the **new** extent of the layer, hence we pass `refresh_entire_image`
1437                      * to the command to make sure that the entire image bounds rect is added
1438                      * to the update rect
1439                      */
1440                     applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1441                     applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1442 
1443                     /**
1444                      * If source layer is **not** animated, then just merge that into the
1445                      * current frame to avoid unintentional destruction of the animation
1446                      * on the layer below. To merge the source into all the frames, just
1447                      * make the source animated.
1448                      *
1449                      * See https://bugs.kde.org/show_bug.cgi?id=475550
1450                      */
1451                     const bool skipMergingSourceLayer = !layer->isAnimated() &&
1452                             frame != currentTimeOnStart;
1453 
1454                     applicator.applyCommand(new MergeLayers(info, skipMergingSourceLayer), KisStrokeJobData::BARRIER);
1455 
1456                     applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage), KisStrokeJobData::BARRIER);
1457                 }
1458             } else {
1459                 applicator.applyCommand(new RefreshHiddenAreas(info));
1460                 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1461                 applicator.applyCommand(new MergeLayers(info, false), KisStrokeJobData::BARRIER);
1462             }
1463 
1464             applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1465             applicator.applyCommand(new CleanUpNodes(info, layer),
1466                                     KisStrokeJobData::SEQUENTIAL,
1467                                     KisStrokeJobData::EXCLUSIVE);
1468             applicator.applyCommand(new KeepMergedNodesSelected(info, true));
1469         } else if (layer->visible()) {
1470             applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1471                                                                  layer, KisNodeSP(),
1472                                                                  image, false));
1473 
1474             applicator.applyCommand(
1475                 new SimpleRemoveLayers(KisNodeList() << prevLayer,
1476                                        image),
1477                 KisStrokeJobData::SEQUENTIAL,
1478                 KisStrokeJobData::EXCLUSIVE);
1479 
1480             applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1481                                                                  KisNodeSP(), layer,
1482                                                                  image, true));
1483         } else if (prevLayer->visible()) {
1484             applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1485                                                                  layer, KisNodeSP(),
1486                                                                  image, false));
1487 
1488             applicator.applyCommand(
1489                 new SimpleRemoveLayers(KisNodeList() << layer,
1490                                        image),
1491                 KisStrokeJobData::SEQUENTIAL,
1492                 KisStrokeJobData::EXCLUSIVE);
1493 
1494             applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1495                                                                  KisNodeSP(), prevLayer,
1496                                                                  image, true));
1497         }
1498 
1499         applicator.end();
1500     }
1501 
1502     bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents)
1503     {
1504         KisNodeList nodeParents;
1505 
1506         KisNodeSP parent = node->parent();
1507         while (parent) {
1508             nodeParents << parent;
1509             parent = parent->parent();
1510         }
1511 
1512         foreach(KisNodeSP perspectiveParent, parents) {
1513             if (nodeParents.contains(perspectiveParent)) {
1514                 return true;
1515             }
1516         }
1517 
1518         return false;
1519     }
1520 
1521     bool checkIsCloneOf(KisNodeSP node, const KisNodeList &nodes)
1522     {
1523         bool result = false;
1524 
1525         KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
1526         if (clone) {
1527             KisNodeSP cloneSource = KisNodeSP(clone->copyFrom());
1528 
1529             Q_FOREACH(KisNodeSP subtree, nodes) {
1530                 result =
1531                     recursiveFindNode(subtree,
1532                                       [cloneSource](KisNodeSP node) -> bool
1533                                       {
1534                                           return node == cloneSource;
1535                                       });
1536 
1537                 if (!result) {
1538                     result = checkIsCloneOf(cloneSource, nodes);
1539                 }
1540 
1541                 if (result) {
1542                     break;
1543                 }
1544             }
1545         }
1546 
1547         return result;
1548     }
1549 
1550     void filterMergeableNodes(KisNodeList &nodes, bool allowMasks)
1551     {
1552         KisNodeList::iterator it = nodes.begin();
1553 
1554         while (it != nodes.end()) {
1555             if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) ||
1556                 checkIsChildOf(*it, nodes)) {
1557                 //qDebug() << "Skipping node" << ppVar((*it)->name());
1558                 it = nodes.erase(it);
1559             } else {
1560                 ++it;
1561             }
1562         }
1563     }
1564 
1565     void sortMergeableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
1566     {
1567         KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root);
1568 
1569         if (it != inputNodes.end()) {
1570             outputNodes << *it;
1571             inputNodes.erase(it);
1572         }
1573 
1574         if (inputNodes.isEmpty()) {
1575             return;
1576         }
1577 
1578         KisNodeSP child = root->firstChild();
1579         while (child) {
1580             sortMergeableNodes(child, inputNodes, outputNodes);
1581             child = child->nextSibling();
1582         }
1583 
1584         /**
1585          * By the end of recursion \p inputNodes must be empty
1586          */
1587         KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty());
1588     }
1589 
1590     KisNodeList sortMergeableNodes(KisNodeSP root, KisNodeList nodes)
1591     {
1592         KisNodeList result;
1593         sortMergeableNodes(root, nodes, result);
1594         return result;
1595     }
1596 
1597     KisNodeList sortAndFilterMergeableInternalNodes(KisNodeList nodes, bool allowMasks)
1598     {
1599         KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1600 
1601         KisNodeSP root;
1602         Q_FOREACH(KisNodeSP node, nodes) {
1603             KisNodeSP localRoot = node;
1604             while (localRoot->parent()) {
1605                 localRoot = localRoot->parent();
1606             }
1607 
1608             if (!root) {
1609                 root = localRoot;
1610             }
1611             KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1612         }
1613 
1614         KisNodeList result;
1615         sortMergeableNodes(root, nodes, result);
1616         filterMergeableNodes(result, allowMasks);
1617         return result;
1618     }
1619 
1620     KisNodeList sortAndFilterAnyMergeableNodesSafe(const KisNodeList &nodes, KisImageSP image) {
1621         KisNodeList filteredNodes = nodes;
1622         KisNodeList sortedNodes;
1623 
1624         KisLayerUtils::filterMergeableNodes(filteredNodes, true);
1625 
1626         bool haveExternalNodes = false;
1627         Q_FOREACH (KisNodeSP node, nodes) {
1628             if (node->graphListener() != image->root()->graphListener()) {
1629                 haveExternalNodes = true;
1630                 break;
1631             }
1632         }
1633 
1634         if (!haveExternalNodes) {
1635             KisLayerUtils::sortMergeableNodes(image->root(), filteredNodes, sortedNodes);
1636         } else {
1637             sortedNodes = filteredNodes;
1638         }
1639 
1640         return sortedNodes;
1641     }
1642 
1643 
1644     void addCopyOfNameTag(KisNodeSP node)
1645     {
1646         const QString prefix = i18n("Copy of");
1647         QString newName = node->name();
1648         if (!newName.startsWith(prefix)) {
1649             newName = QString("%1 %2").arg(prefix).arg(newName);
1650             node->setName(newName);
1651         }
1652     }
1653 
1654     KisNodeList findNodesWithProps(KisNodeSP root, const KoProperties &props, bool excludeRoot)
1655     {
1656         KisNodeList nodes;
1657 
1658         if ((!excludeRoot || root->parent()) && root->check(props)) {
1659             nodes << root;
1660         }
1661 
1662         KisNodeSP node = root->firstChild();
1663         while (node) {
1664             nodes += findNodesWithProps(node, props, excludeRoot);
1665             node = node->nextSibling();
1666         }
1667 
1668         return nodes;
1669     }
1670 
1671     KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
1672     {
1673         KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; }
1674         KIS_ASSERT_RECOVER(putAfter) { return nodes; }
1675 
1676         KisNodeList visibleNodes;
1677         int putAfterIndex = -1;
1678 
1679         Q_FOREACH(KisNodeSP node, nodes) {
1680             if (node->visible() || node->userLocked()) {
1681                 visibleNodes << node;
1682             } else {
1683                 *invisibleNodes << node;
1684 
1685                 if (node == *putAfter) {
1686                     putAfterIndex = visibleNodes.size() - 1;
1687                 }
1688             }
1689         }
1690 
1691         if (!visibleNodes.isEmpty() && putAfterIndex >= 0) {
1692             putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1);
1693             *putAfter = visibleNodes[putAfterIndex];
1694         }
1695 
1696         return visibleNodes;
1697     }
1698 
1699     void filterUnlockedNodes(KisNodeList &nodes)
1700     {
1701         KisNodeList::iterator it = nodes.begin();
1702 
1703         while (it != nodes.end()) {
1704             if ((*it)->userLocked()) {
1705                 it = nodes.erase(it);
1706             } else {
1707                 ++it;
1708             }
1709         }
1710     }
1711 
1712     void changeImageDefaultProjectionColor(KisImageSP image, const KoColor &color)
1713     {
1714         KisImageSignalVector emitSignals;
1715         KisProcessingApplicator applicator(image,
1716                                            image->root(),
1717                                            KisProcessingApplicator::RECURSIVE,
1718                                            emitSignals,
1719                                            kundo2_i18n("Change projection color"),
1720                                            0,
1721                                            KisCommandUtils::ChangeProjectionColorCommand);
1722         applicator.applyCommand(new KisChangeProjectionColorCommand(image, color), KisStrokeJobData::BARRIER, KisStrokeJobData::EXCLUSIVE);
1723         applicator.end();
1724     }
1725 
1726     struct EphemeralCommandsWrapper : KisCommandUtils::AggregateCommand
1727     {
1728         EphemeralCommandsWrapper(MergeMultipleInfoSP info, QVector<KUndo2Command*> commands, bool cleanupNodes)
1729             : m_info(info)
1730             , m_commands(commands)
1731             , m_cleanupNodes(cleanupNodes)
1732         {
1733         }
1734 
1735         void populateChildCommands() {
1736             if (!m_cleanupNodes && !m_info->ephemeralCommandsStore) {
1737                 m_info->ephemeralCommandsStore.reset(new KisSurrogateUndoStore());
1738             }
1739 
1740             Q_FOREACH (KUndo2Command *cmd, m_commands) {
1741                 if (m_cleanupNodes) {
1742                     addCommand(cmd);
1743                 } else {
1744                     m_info->ephemeralCommandsStore->addCommand(cmd);
1745                 }
1746             }
1747             m_commands.clear();
1748             m_info.reset();
1749         }
1750 
1751     private:
1752         MergeMultipleInfoSP m_info;
1753         QVector<KUndo2Command*> m_commands;
1754         bool m_cleanupNodes {true};
1755     };
1756 
1757     struct UndoEphemeralCommands : KisCommandUtils::AggregateCommand
1758     {
1759         UndoEphemeralCommands(MergeMultipleInfoSP info)
1760             : m_info(info)
1761         {
1762         }
1763 
1764         void populateChildCommands() {
1765             KIS_SAFE_ASSERT_RECOVER_RETURN(m_info->ephemeralCommandsStore);
1766             m_info->ephemeralCommandsStore->undoAll();
1767 
1768         }
1769 
1770     private:
1771         MergeMultipleInfoSP m_info;
1772     };
1773 
1774     /**
1775      * There might be two approaches for merging multiple layers:
1776      *
1777      * 1) Consider the selected nodes as a distinct "group" and merge them
1778      *    as if they were isolated from the rest of the image. The key point
1779      *    of this approach is that the look of the image will change, when
1780      *    merging "weird" layers, like adjustment layers or layers with
1781      *    non-normal blending mode.
1782      *
1783      * 2) Merge layers in a way to keep the look of the image as unchanged as
1784      *    possible. With this approach one uses a few heuristics:
1785      *
1786      *       * when merging multiple layers with non-normal (but equal) blending
1787      *         mode, first merge these layers together using Normal blending mode,
1788      *         then set blending mode of the result to the original blending mode
1789      *
1790      *       * when merging multiple layers with different blending modes or
1791      *         layer styles, they are first rasterized, and then laid over each
1792      *         other with their own composite op. The blending mode of the final
1793      *         layer is set to Normal, so the user could clearly see that he should
1794      *         choose the correct blending mode.
1795      *
1796      * Krita uses the second approach: after merge operation, the image should look
1797      * as if nothing has happened (if it is technically possible).
1798      */
1799     void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter,
1800                                            bool flattenSingleLayer, const KUndo2MagicString &actionName,
1801                                            bool cleanupNodes = true, const QString layerName = QString())
1802     {
1803         if (!putAfter) {
1804             putAfter = mergedNodes.first();
1805         }
1806 
1807         filterMergeableNodes(mergedNodes);
1808         {
1809             KisNodeList tempNodes;
1810             std::swap(mergedNodes, tempNodes);
1811             sortMergeableNodes(image->root(), tempNodes, mergedNodes);
1812         }
1813 
1814         if (mergedNodes.size() <= 1 &&
1815             (!flattenSingleLayer && mergedNodes.size() == 1)) return;
1816 
1817         KisImageSignalVector emitSignals;
1818         emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes);
1819 
1820 
1821 
1822         KisNodeList originalNodes = mergedNodes;
1823         KisNodeList invisibleNodes;
1824         mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter);
1825 
1826         if (mergedNodes.isEmpty()) return;
1827 
1828 
1829         // make sure we don't add the new layer into a locked group
1830         KIS_SAFE_ASSERT_RECOVER_RETURN(putAfter->parent());
1831         while (putAfter->parent() && !putAfter->parent()->isEditable()) {
1832             putAfter = putAfter->parent();
1833         }
1834 
1835         /**
1836          * We have reached the root of the layer hierarchy and didn't manage
1837          * to find a node that was editable enough for putting our merged
1838          * result into it. That shouldn't happen in normal circumstances,
1839          * unless the user chose to make the root layer visible and lock
1840          * it manually.
1841          */
1842         if (!putAfter->parent()) {
1843             return;
1844         }
1845 
1846         KisProcessingApplicator applicator(image, 0,
1847                                            KisProcessingApplicator::NONE,
1848                                            emitSignals,
1849                                            actionName);
1850 
1851 
1852         if (!invisibleNodes.isEmpty() && cleanupNodes) {
1853 
1854             /* If the putAfter node is invisible,
1855              * we should instead pick one of the nodes
1856              * to be merged to avoid a null putAfter
1857              * after we remove all invisible layers from
1858              * the image.
1859              * (The assumption is that putAfter is among
1860              * the layers to merge, so if it's invisible,
1861              * it's going to be removed)
1862              */
1863             if (!putAfter->visible()){
1864                 putAfter = mergedNodes.first();
1865             }
1866 
1867             applicator.applyCommand(
1868                 new SimpleRemoveLayers(invisibleNodes,
1869                                        image),
1870                 KisStrokeJobData::SEQUENTIAL,
1871                 KisStrokeJobData::EXCLUSIVE);
1872         }
1873 
1874         if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) {
1875             MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes));
1876 
1877             // disable key strokes on all colorize masks, all onion skins on
1878             // paint layers and wait until update is finished with a barrier
1879             //
1880             // when doing "new layer from visible" we should undo these changes
1881             // before the action stops, because the source layers are **not**
1882             // removed as a result of this action
1883             applicator.applyCommand(
1884                 new EphemeralCommandsWrapper(info,
1885                                              {
1886                                               new DisableColorizeKeyStrokes(info),
1887                                               new DisableOnionSkins(info),
1888                                               new DisablePassThroughForHeadsOnly(info)
1889                                              },
1890                                              cleanupNodes));
1891             applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1892 
1893             applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false));
1894             applicator.applyCommand(new FillSelectionMasks(info));
1895             applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER);
1896             applicator.applyCommand(new EphemeralCommandsWrapper(info, { new DisableExtraCompositing(info) } , cleanupNodes));
1897             applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1898 
1899             if (!info->frames.isEmpty()) {
1900                 foreach (int frame, info->frames) {
1901                     applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1902 
1903                     applicator.applyCommand(new AddNewFrame(info, frame));
1904                     /**
1905                      * When switching frames we need to update the entire image, not
1906                      * only the **new** extent of the layer, hence we pass `refresh_entire_image`
1907                      * to the command to make sure that the entire image bounds rect is added
1908                      * to the update rect
1909                      */
1910                     applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1911                     applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1912                     applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1913 
1914                     applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
1915                 }
1916             } else {
1917                 applicator.applyCommand(new RefreshHiddenAreas(info));
1918                 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1919                 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1920             }
1921 
1922             //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1923             if (cleanupNodes){
1924                 applicator.applyCommand(new CleanUpNodes(info, putAfter),
1925                                             KisStrokeJobData::SEQUENTIAL,
1926                                         KisStrokeJobData::EXCLUSIVE);
1927             } else {
1928                 applicator.applyCommand(new UndoEphemeralCommands(info));
1929                 applicator.applyCommand(new InsertNode(info, putAfter),
1930                                             KisStrokeJobData::SEQUENTIAL,
1931                                         KisStrokeJobData::EXCLUSIVE);
1932             }
1933 
1934             applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true));
1935         }
1936 
1937         applicator.end();
1938 
1939     }
1940 
1941     void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
1942     {
1943         mergeMultipleLayersImpl(image, mergedNodes, putAfter, false, kundo2_i18n("Merge Selected Nodes"));
1944     }
1945 
1946     void newLayerFromVisible(KisImageSP image, KisNodeSP putAfter)
1947     {
1948         KisNodeList mergedNodes;
1949         mergedNodes << image->root();
1950 
1951         mergeMultipleLayersImpl(image, mergedNodes, putAfter, true, kundo2_i18n("New From Visible"), false, i18nc("New layer created from all the visible layers", "Visible"));
1952     }
1953 
1954     struct MergeSelectionMasks : public KisCommandUtils::AggregateCommand {
1955         MergeSelectionMasks(MergeDownInfoBaseSP info, KisNodeSP putAfter)
1956             : m_info(info),
1957               m_putAfter(putAfter){}
1958 
1959         void populateChildCommands() override {
1960             KisNodeSP parent;
1961             CleanUpNodes::findPerfectParent(m_info->allSrcNodes(), m_putAfter, parent);
1962 
1963             KisLayerSP parentLayer;
1964             do {
1965                 parentLayer = qobject_cast<KisLayer*>(parent.data());
1966 
1967                 parent = parent->parent();
1968             } while(!parentLayer && parent);
1969 
1970             KisSelectionSP selection = new KisSelection();
1971 
1972             foreach (KisNodeSP node, m_info->allSrcNodes()) {
1973                 KisMaskSP mask = dynamic_cast<KisMask*>(node.data());
1974                 if (!mask) continue;
1975 
1976                 selection->pixelSelection()->applySelection(
1977                     mask->selection()->pixelSelection(), SELECTION_ADD);
1978             }
1979 
1980             KisSelectionMaskSP mergedMask = new KisSelectionMask(m_info->image, i18n("Selection Mask"));
1981             mergedMask->initSelection(parentLayer);
1982             mergedMask->setSelection(selection);
1983 
1984             m_info->dstNode = mergedMask;
1985         }
1986 
1987     private:
1988         MergeDownInfoBaseSP m_info;
1989         KisNodeSP m_putAfter;
1990     };
1991 
1992     struct ActivateSelectionMask : public KisCommandUtils::AggregateCommand {
1993         ActivateSelectionMask(MergeDownInfoBaseSP info)
1994             : m_info(info) {}
1995 
1996         void populateChildCommands() override {
1997             KisSelectionMaskSP mergedMask = dynamic_cast<KisSelectionMask*>(m_info->dstNode.data());
1998             addCommand(new KisActivateSelectionMaskCommand(mergedMask, true));
1999         }
2000 
2001     private:
2002         MergeDownInfoBaseSP m_info;
2003     };
2004 
2005     bool tryMergeSelectionMasks(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
2006     {
2007         QList<KisSelectionMaskSP> selectionMasks;
2008 
2009         for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) {
2010             KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data());
2011             if (!mask) {
2012                 it = mergedNodes.erase(it);
2013             } else {
2014                 selectionMasks.append(mask);
2015                 ++it;
2016             }
2017         }
2018 
2019         if (mergedNodes.isEmpty()) return false;
2020 
2021         KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data());
2022         KIS_ASSERT_RECOVER(parentLayer) { return 0; }
2023 
2024         KisImageSignalVector emitSignals;
2025 
2026         KisProcessingApplicator applicator(image, 0,
2027                                            KisProcessingApplicator::NONE,
2028                                            emitSignals,
2029                                            kundo2_i18n("Merge Selection Masks"));
2030 
2031         MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes));
2032 
2033 
2034         applicator.applyCommand(new MergeSelectionMasks(info, putAfter));
2035         applicator.applyCommand(new CleanUpNodes(info, putAfter),
2036                                 KisStrokeJobData::SEQUENTIAL,
2037                                 KisStrokeJobData::EXCLUSIVE);
2038         applicator.applyCommand(new ActivateSelectionMask(info));
2039         applicator.end();
2040 
2041         return true;
2042     }
2043 
2044     void flattenLayer(KisImageSP image, KisLayerSP layer)
2045     {
2046         if (!layer->childCount() && !layer->layerStyle())
2047             return;
2048 
2049         KisNodeList mergedNodes;
2050         mergedNodes << layer;
2051 
2052         mergeMultipleLayersImpl(image, mergedNodes, layer, true, kundo2_i18n("Flatten Layer"));
2053     }
2054 
2055     void flattenImage(KisImageSP image, KisNodeSP activeNode)
2056     {
2057         if (!activeNode) {
2058             activeNode = image->root()->lastChild();
2059         }
2060 
2061 
2062         KisNodeList mergedNodes;
2063         mergedNodes << image->root();
2064 
2065         mergeMultipleLayersImpl(image, mergedNodes, activeNode, true, kundo2_i18n("Flatten Image"));
2066     }
2067 
2068     KisSimpleUpdateCommand::KisSimpleUpdateCommand(KisNodeList nodes, bool finalize, KUndo2Command *parent)
2069         : FlipFlopCommand(finalize, parent),
2070           m_nodes(nodes)
2071     {
2072     }
2073     void KisSimpleUpdateCommand::partB()
2074     {
2075         updateNodes(m_nodes);
2076     }
2077     void KisSimpleUpdateCommand::updateNodes(const KisNodeList &nodes)
2078     {
2079         Q_FOREACH(KisNodeSP node, nodes) {
2080             node->setDirty(node->extent());
2081         }
2082     }
2083 
2084     KisNodeSP recursiveFindNode(KisNodeSP node, std::function<bool(KisNodeSP)> func)
2085     {
2086         if (func(node)) {
2087             return node;
2088         }
2089 
2090         node = node->firstChild();
2091         while (node) {
2092             KisNodeSP resultNode = recursiveFindNode(node, func);
2093             if (resultNode) {
2094                 return resultNode;
2095             }
2096             node = node->nextSibling();
2097         }
2098 
2099         return 0;
2100     }
2101 
2102     KisNodeSP findNodeByUuid(KisNodeSP root, const QUuid &uuid)
2103     {
2104         return recursiveFindNode(root,
2105             [uuid] (KisNodeSP node) {
2106                 return node->uuid() == uuid;
2107         });
2108     }
2109 
2110     QList<KisNodeSP> findNodesByName(KisNodeSP root, const QString &name, bool recursive, bool partialMatch)
2111     {
2112         KisNodeList nodeList;
2113         KisNodeSP child = root->firstChild();
2114 
2115         while (child) {
2116             if (name.isEmpty() || (!partialMatch && child->name() == name) || (partialMatch && child->name().contains(name, Qt::CaseInsensitive))) {
2117                 nodeList << child;
2118             }
2119             if (recursive && child->childCount() > 0) {
2120                 nodeList << findNodesByName(child, name, recursive, partialMatch);
2121             }
2122             child = child->nextSibling();
2123         }
2124 
2125         return nodeList;
2126     }
2127 
2128     KisNodeSP findNodeByName(KisNodeSP root, const QString &name)
2129     {
2130         return recursiveFindNode(root,
2131             [name] (KisNodeSP node) {
2132                 return node->name() == name;
2133         });
2134     }
2135 
2136     void forceAllDelayedNodesUpdate(KisNodeSP root)
2137     {
2138         KisLayerUtils::recursiveApplyNodes(root,
2139         [] (KisNodeSP node) {
2140             KisDelayedUpdateNodeInterface *delayedUpdate =
2141                     dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2142             if (delayedUpdate) {
2143                 delayedUpdate->forceUpdateTimedNode();
2144             }
2145         });
2146     }
2147 
2148     bool hasDelayedNodeWithUpdates(KisNodeSP root)
2149     {
2150         return recursiveFindNode(root,
2151             [] (KisNodeSP node) {
2152                 KisDelayedUpdateNodeInterface *delayedUpdate =
2153                     dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2154 
2155                 return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false;
2156             });
2157     }
2158 
2159     void forceAllHiddenOriginalsUpdate(KisNodeSP root)
2160     {
2161         KisLayerUtils::recursiveApplyNodes(root,
2162         [] (KisNodeSP node) {
2163             KisCroppedOriginalLayerInterface *croppedUpdate =
2164                     dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data());
2165             if (croppedUpdate) {
2166                 croppedUpdate->forceUpdateHiddenAreaOnOriginal();
2167             }
2168         });
2169     }
2170 
2171     KisImageSP findImageByHierarchy(KisNodeSP node)
2172     {
2173         while (node) {
2174             const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data());
2175             if (layer) {
2176                 return layer->image();
2177             }
2178 
2179             node = node->parent();
2180         }
2181 
2182         return 0;
2183     }
2184 
2185     namespace Private {
2186     QRect realNodeChangeRect(KisNodeSP rootNode, QRect currentRect = QRect()) {
2187         KisNodeSP node = rootNode->firstChild();
2188 
2189         while(node) {
2190             currentRect |= realNodeChangeRect(node, currentRect);
2191             node = node->nextSibling();
2192         }
2193 
2194         if (!rootNode->isFakeNode() && !rootNode->projectionLeaf()->isMask()) {
2195             // TODO: it would be better to count up changeRect inside
2196             // node's extent() method
2197             //
2198             // NOTE: when flattening a group layer, we should take the change rect of the
2199             // all the child layers as the source of the change. We are calculating
2200             // the change rect **before** the update itself, therefore rootNode->exactBounds()
2201             // is not yet prepared, hence its exact bounds still contail old values.
2202             currentRect |= rootNode->projectionPlane()->changeRect(rootNode->exactBounds() | currentRect);
2203         }
2204 
2205         return currentRect;
2206     }
2207     }
2208 
2209 namespace Private {
2210     void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea, const QRect &extraUpdateRect) {
2211         QRect realNodeRect = Private::realNodeChangeRect(rootNode) | extraUpdateRect;
2212         if (!preparedArea.contains(realNodeRect)) {
2213 
2214             QRegion dirtyRegion = realNodeRect;
2215             dirtyRegion -= preparedArea;
2216 
2217             auto rc = dirtyRegion.begin();
2218             while (rc != dirtyRegion.end()) {
2219                 image->refreshGraphAsync(rootNode, *rc, realNodeRect);
2220                 rc++;
2221             }
2222         }
2223     }
2224 } // namespace Private
2225 
2226     void refreshHiddenAreaAsync(KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea) {
2227         Private::refreshHiddenAreaAsync(image, rootNode, preparedArea, QRect());
2228     }
2229 
2230     QRect recursiveTightNodeVisibleBounds(KisNodeSP rootNode)
2231     {
2232         QRect exactBounds;
2233         recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) {
2234             exactBounds |= node->projectionPlane()->tightUserVisibleBounds();
2235         });
2236         return exactBounds;
2237     }
2238 
2239     KisNodeSP findRoot(KisNodeSP node)
2240     {
2241         if (!node) return node;
2242 
2243         while (node->parent()) {
2244             node = node->parent();
2245         }
2246         return node;
2247     }
2248 
2249     bool canChangeImageProfileInvisibly(KisImageSP image)
2250     {
2251         int numLayers = 0;
2252         bool hasNonNormalLayers = false;
2253         bool hasTransparentLayer = false;
2254 
2255 
2256         recursiveApplyNodes(image->root(),
2257             [&numLayers, &hasNonNormalLayers, &hasTransparentLayer, image] (KisNodeSP node) {
2258                 if (!node->inherits("KisLayer")) return;
2259 
2260                 numLayers++;
2261 
2262                 if (node->exactBounds().isEmpty()) return;
2263 
2264                 // this is only an approximation! it is not exact!
2265                 if (!hasTransparentLayer &&
2266                     node->exactBounds() != image->bounds()) {
2267 
2268                     hasTransparentLayer = true;
2269                 }
2270 
2271                 if (!hasNonNormalLayers &&
2272                     node->compositeOpId() != COMPOSITE_OVER) {
2273 
2274                     hasNonNormalLayers = true;
2275                 }
2276             });
2277 
2278         return numLayers == 1 || (!hasNonNormalLayers && !hasTransparentLayer);
2279     }
2280 
2281     void splitAlphaToMask(KisImageSP image, KisNodeSP node, const QString& maskName)
2282     {
2283         SplitAlphaToMaskInfoSP info( new SplitAlphaToMaskInfo(node->image(), node, maskName) );
2284 
2285         KisImageSignalVector emitSignals;
2286         KisProcessingApplicator applicator(image, 0,
2287                                            KisProcessingApplicator::NONE,
2288                                            emitSignals,
2289                                            kundo2_i18n("Split Alpha into a Mask"));
2290 
2291         applicator.applyCommand(new SimpleAddNode(info->image, info->getMask(), info->node), KisStrokeJobData::BARRIER);
2292         applicator.applyCommand(new InitSplitAlphaSelectionMask(info));
2293         if (info->frames.count() > 0) {
2294             Q_FOREACH(const int& frame, info->frames) {
2295                 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
2296                 applicator.applyCommand(new AddNewFrame(info->getMask(), frame, info->node));
2297                 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2298                 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
2299             }
2300         } else {
2301             applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2302         }
2303         applicator.end();
2304     }
2305 
2306     std::future<KisNodeSP> convertToPaintLayer(KisImageSP image, KisNodeSP src)
2307     {
2308         //Initialize all operation dependencies.
2309         ConvertToPaintLayerInfoSP info( new ConvertToPaintLayerInfo(image, src) );
2310 
2311         if (!info->hasTargetNode())
2312             return kismpl::make_ready_future(KisNodeSP());
2313 
2314         KisImageSignalVector emitSignals;
2315         KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Convert to a Paint Layer"));
2316 
2317         applicator.applyCommand(new SimpleAddNode(info->image(), info->targetNode(), info->insertionParent(), info->insertionPutAfter()), KisStrokeJobData::BARRIER);
2318 
2319         if (info->frames().count() > 0) {
2320             Q_FOREACH(const int& frame, info->frames()) {
2321                 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, false, info->storage));
2322                 applicator.applyCommand(new RefreshDelayedUpdateLayers(info->sourceNodes()), KisStrokeJobData::BARRIER);
2323                 applicator.applyCommand(new RefreshHiddenAreas(info->image(), info->sourceNode()), KisStrokeJobData::BARRIER);
2324                 applicator.applyCommand(new AddNewFrame(info->targetNode(), frame, info->sourceNode()), KisStrokeJobData::BARRIER);
2325                 applicator.applyCommand(new UploadProjectionToFrameCommand(info->sourceNode(), info->targetNode(), frame));
2326                 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, true, info->storage));
2327             }
2328         }
2329 
2330         applicator.applyCommand(new SimpleRemoveLayers(info->toRemove(), info->image()));
2331 
2332         applicator.end();
2333 
2334         return kismpl::then(applicator.successfullyCompletedFuture(),
2335             [node = info->targetNode()] (std::future<bool> completed) {
2336                 return completed.get() ? node : KisNodeSP();
2337             });
2338     }
2339 
2340     //===========================================================
2341 
2342     int fetchLayerActiveRasterFrameID(KisNodeSP node)
2343     {
2344         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  -1);
2345         KisPaintDeviceSP paintDevice = node->paintDevice();
2346         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2347 
2348         if (!paintDevice->keyframeChannel()) {
2349             return -1;
2350         }
2351 
2352         const int activeTime = paintDevice->keyframeChannel()->activeKeyframeTime();
2353         KisRasterKeyframeSP keyframe = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(activeTime);
2354         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(keyframe, -1);
2355 
2356         return keyframe->frameID();
2357     }
2358 
2359     int fetchLayerActiveRasterFrameTime(KisNodeSP node)
2360     {
2361         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  -1);
2362         KisPaintDeviceSP paintDevice = node->paintDevice();
2363         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2364 
2365         if (!paintDevice->keyframeChannel()) {
2366             return -1;
2367         }
2368 
2369         return paintDevice->keyframeChannel()->activeKeyframeTime();
2370     }
2371 
2372     KisTimeSpan fetchLayerActiveRasterFrameSpan(KisNodeSP node, const int time)
2373     {
2374         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  KisTimeSpan::infinite(0));
2375         KisPaintDeviceSP paintDevice = node->paintDevice();
2376         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, KisTimeSpan::infinite(0));
2377         if (!paintDevice->keyframeChannel()) {
2378             return KisTimeSpan::infinite(0);
2379         }
2380 
2381         return paintDevice->keyframeChannel()->affectedFrames(time);
2382     }
2383 
2384     QSet<int> fetchLayerIdenticalRasterFrameTimes(KisNodeSP node, const int &frameTime)
2385     {
2386         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  QSet<int>());
2387         KisPaintDeviceSP paintDevice = node->paintDevice();
2388         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2389         if (!paintDevice->keyframeChannel()) {
2390             return QSet<int>();
2391         }
2392 
2393         return paintDevice->keyframeChannel()->clonesOf(node.data(), frameTime);
2394     }
2395 
2396     /* Finds all frames matching a specific frame ID. useful to filter out duplicate frames. */
2397     QSet<int> fetchLayerRasterFrameTimesMatchingID(KisNodeSP node, const int frameID) {
2398         KIS_ASSERT(node);
2399         KisRasterKeyframeChannel* rasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false));
2400 
2401         if (!rasterChannel) {
2402             return QSet<int>();
2403         }
2404 
2405         return rasterChannel->timesForFrameID(frameID);
2406     }
2407 
2408     QSet<int> fetchLayerRasterIDsAtTimes(KisNodeSP node, const QSet<int> &times)
2409     {
2410         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  QSet<int>());
2411         KisPaintDeviceSP paintDevice = node->paintDevice();
2412         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2413         if (!paintDevice->keyframeChannel()) {
2414             return QSet<int>();
2415         }
2416 
2417         QSet<int> frameIDs;
2418 
2419         Q_FOREACH( const int& frame, times ) {
2420             KisRasterKeyframeSP raster = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(frame);
2421             frameIDs << raster->frameID();
2422         }
2423 
2424         return frameIDs;
2425     }
2426 
2427     QSet<int> filterTimesForOnlyRasterKeyedTimes(KisNodeSP node, const QSet<int> &times)
2428     {
2429         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  times);
2430         KisPaintDeviceSP paintDevice = node->paintDevice();
2431         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, times);
2432         if (!paintDevice->keyframeChannel()) {
2433             return times;
2434         }
2435 
2436         return paintDevice->keyframeChannel()->allKeyframeTimes().intersect(times);
2437     }
2438 
2439     QSet<int> fetchLayerUniqueRasterTimesMatchingIDs(KisNodeSP node, QSet<int>& frameIDs)
2440     {
2441         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node,  QSet<int>());
2442         KisPaintDeviceSP paintDevice = node->paintDevice();
2443         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2444         KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice->framesInterface(), QSet<int>());
2445 
2446         QSet<int> uniqueTimes;
2447 
2448         Q_FOREACH( const int& id, frameIDs) {
2449             QSet<int> times = fetchLayerRasterFrameTimesMatchingID(node, id);
2450             if (times.count() > 0) {
2451                 uniqueTimes.insert(*times.begin());
2452             }
2453         }
2454 
2455         return uniqueTimes;
2456     }
2457 
2458     QSet<int> fetchUniqueFrameTimes(KisNodeSP node, QSet<int> selectedTimes, bool filterActiveFrameID)
2459     {
2460         if (selectedTimes.isEmpty() || !node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id()))
2461             return selectedTimes;
2462 
2463         // Convert a set of selected keyframe times into set of selected "frameIDs"...
2464         QSet<int> selectedFrameIDs = KisLayerUtils::fetchLayerRasterIDsAtTimes(node, selectedTimes);
2465 
2466         if (filterActiveFrameID) {
2467             // Current frame was already filtered e.g. during filter preview in `KisFilterManager::apply`...
2468             // So let's remove it...
2469             const int currentActiveFrameID = KisLayerUtils::fetchLayerActiveRasterFrameID(node);
2470             selectedFrameIDs.remove(currentActiveFrameID);
2471         }
2472 
2473         // Convert frameIDs to any arbitrary frame time associated with the frameID...
2474         QSet<int> uniqueFrameTimes = node->paintDevice()->framesInterface() ? KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs(node, selectedFrameIDs) : QSet<int>();
2475 
2476         return uniqueFrameTimes;
2477     }
2478 
2479 }