File indexing completed on 2024-05-12 16:01:33

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Boudewijn Rempt <boud@valdyas.org>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-or-later
0005  */
0006 
0007 #include "kis_mimedata.h"
0008 #include "kis_config.h"
0009 #include "kis_node.h"
0010 #include "kis_paint_device.h"
0011 #include "kis_shared_ptr.h"
0012 #include "kis_image.h"
0013 #include "kis_layer.h"
0014 #include "kis_shape_layer.h"
0015 #include "kis_paint_layer.h"
0016 #include "kis_clone_layer.h"
0017 #include "KisDocument.h"
0018 #include "kis_shape_controller.h"
0019 #include "KisPart.h"
0020 #include "kis_layer_utils.h"
0021 #include "kis_generator_registry.h"
0022 #include "KisGlobalResourcesInterface.h"
0023 #include "kis_filter_configuration.h"
0024 #include "kis_generator_layer.h"
0025 #include "kis_selection.h"
0026 #include "kis_node_insertion_adapter.h"
0027 #include "kis_dummies_facade_base.h"
0028 #include "kis_node_dummies_graph.h"
0029 #include "KisImportExportManager.h"
0030 #include "KisImageBarrierLockerWithFeedback.h"
0031 
0032 #include <KoProperties.h>
0033 #include <KoStore.h>
0034 #include <KoColorProfile.h>
0035 #include <KoColorSpaceRegistry.h>
0036 
0037 #include <QApplication>
0038 #include <QImage>
0039 #include <QByteArray>
0040 #include <QBuffer>
0041 #include <QDomDocument>
0042 #include <QDomElement>
0043 #include <QDesktopWidget>
0044 #include <QDir>
0045 
0046 namespace {
0047 KisNodeSP safeCopyNode(KisNodeSP node, bool detachClones = true) {
0048     KisCloneLayerSP cloneLayer = dynamic_cast<KisCloneLayer*>(node.data());
0049     return cloneLayer && detachClones ?
0050         KisNodeSP(cloneLayer->reincarnateAsPaintLayer()) : node->clone();
0051 }
0052 }
0053 
0054 
0055 KisMimeData::KisMimeData(QList<KisNodeSP> nodes, KisImageSP image, bool forceCopy)
0056     : QMimeData()
0057     , m_nodes(nodes)
0058     , m_forceCopy(forceCopy)
0059     , m_image(image)
0060 {
0061     Q_ASSERT(m_nodes.size() > 0);
0062 
0063     KIS_SAFE_ASSERT_RECOVER_RETURN(image);
0064 
0065     Q_FOREACH (KisNodeSP node, nodes) {
0066         m_copiedBounds |= KisLayerUtils::recursiveTightNodeVisibleBounds(node);
0067     }
0068 }
0069 
0070 void KisMimeData::deepCopyNodes()
0071 {
0072     KisNodeList newNodes;
0073 
0074     {
0075         KisImageBarrierLockerWithFeedbackAllowNull locker(m_image);
0076         Q_FOREACH (KisNodeSP node, m_nodes) {
0077             KisNodeSP newNode = safeCopyNode(node);
0078             newNode->setImage(nullptr);
0079 
0080             newNodes << newNode;
0081         }
0082     }
0083 
0084     m_nodes = newNodes;
0085     m_image = 0;
0086 }
0087 
0088 QList<KisNodeSP> KisMimeData::nodes() const
0089 {
0090     return m_nodes;
0091 }
0092 
0093 QStringList KisMimeData::formats () const
0094 {
0095     QStringList f = QMimeData::formats();
0096     if (m_nodes.size() > 0) {
0097         f << "application/x-qt-image"
0098           << "application/zip"
0099           << "application/x-krita-node-internal-pointer";
0100     }
0101     return f;
0102 }
0103 
0104 KisDocument *createDocument(QList<KisNodeSP> nodes, KisImageSP srcImage, const QRect &copiedBounds)
0105 {
0106     KisDocument *doc = KisPart::instance()->createTemporaryDocument();
0107     QRect rc = copiedBounds;
0108 
0109     QRect offset(0, 0, rc.width(), rc.height());
0110     rc |= offset;
0111 
0112     if (rc.isEmpty() && srcImage) {
0113         rc = srcImage->bounds();
0114     }
0115 
0116     KisImageSP image = new KisImage(0, rc.width(), rc.height(), nodes.first()->colorSpace(), nodes.first()->name());
0117     image->setAllowMasksOnRootNode(true);
0118 
0119     if (srcImage) {
0120         image->setResolution(srcImage->xRes(), srcImage->yRes());
0121     }
0122 
0123     {
0124         KisImageBarrierLockerWithFeedbackAllowNull locker(srcImage);
0125         Q_FOREACH (KisNodeSP node, nodes) {
0126             KisNodeSP clonedNode = safeCopyNode(node);
0127             /// HACK ALERT: here we just initilize parent image link
0128             ///             and skip initilizing shapeController!
0129             ///             Ideally, we should call initializeExternalNode()
0130             ///             instead.
0131             image->addNode(clonedNode);
0132             KIS_SAFE_ASSERT_RECOVER(clonedNode->image() == KisImageWSP(image)) {
0133                 clonedNode->setImage(image);
0134             }
0135         }
0136     }
0137 
0138     doc->setCurrentImage(image);
0139 
0140     return doc;
0141 }
0142 
0143 QByteArray serializeToByteArray(QList<KisNodeSP> nodes, KisImageSP srcImage, const QRect &copiedBounds)
0144 {
0145     QScopedPointer<KisDocument> doc(createDocument(nodes, srcImage, copiedBounds));
0146     QByteArray result = doc->serializeToNativeByteArray();
0147 
0148     // avoid a sanity check failure caused by the fact that the image outlives
0149     // the document (and it does)
0150     doc->setCurrentImage(0);
0151 
0152     return result;
0153 }
0154 
0155 QVariant KisMimeData::retrieveData(const QString &mimetype, QVariant::Type preferredType) const
0156 {
0157     /**
0158      * HACK ALERT:
0159      *
0160      * Sometimes Qt requests the data *after* destruction of Krita,
0161      * we cannot load the nodes in that case, because we need signals
0162      * and timers. So we just skip serializing.
0163      */
0164     if (!QApplication::instance()) return QVariant();
0165 
0166 
0167     Q_ASSERT(m_nodes.size() > 0);
0168 
0169     if (mimetype == "application/x-qt-image") {
0170         KisConfig cfg(true);
0171 
0172         QScopedPointer<KisDocument> doc(createDocument(m_nodes, m_image, m_copiedBounds));
0173 
0174         return doc->image()->projection()->convertToQImage(cfg.displayProfile(QApplication::desktop()->screenNumber(qApp->activeWindow())),
0175                                                            KoColorConversionTransformation::internalRenderingIntent(),
0176                                                            KoColorConversionTransformation::internalConversionFlags());
0177     }
0178     else if (mimetype == "application/zip") {
0179 
0180         QByteArray ba = serializeToByteArray(m_nodes, m_image, m_copiedBounds);
0181         return ba;
0182 
0183     }
0184     else if (mimetype == "application/x-krita-node-internal-pointer") {
0185 
0186         QDomDocument doc("krita_internal_node_pointer");
0187         QDomElement root = doc.createElement("pointer");
0188         root.setAttribute("application_pid", (qint64)QApplication::applicationPid());
0189         root.setAttribute("force_copy", m_forceCopy);
0190         root.setAttribute("image_pointer_value", (qint64)m_image.data());
0191         doc.appendChild(root);
0192 
0193         Q_FOREACH (KisNodeSP node, m_nodes) {
0194             QDomElement element = doc.createElement("node");
0195             element.setAttribute("pointer_value", (qint64)node.data());
0196             root.appendChild(element);
0197         }
0198 
0199         return doc.toByteArray();
0200 
0201     }
0202     else {
0203         return QMimeData::retrieveData(mimetype, preferredType);
0204     }
0205 }
0206 
0207 void KisMimeData::initializeExternalNode(KisNodeSP *node,
0208                                          KisImageSP srcImage,
0209                                          KisImageSP dstImage,
0210                                          KisShapeController *shapeController)
0211 {
0212     KisShapeLayer *shapeLayer = dynamic_cast<KisShapeLayer*>(node->data());
0213     if (shapeLayer) {
0214         // attach the layer to a new shape controller
0215         KisShapeLayer *shapeLayer2 = new KisShapeLayer(*shapeLayer, shapeController);
0216 
0217         if (srcImage
0218             && (!qFuzzyCompare(dstImage->xRes(), srcImage->xRes())
0219                 || !qFuzzyCompare(dstImage->yRes(), srcImage->yRes()))) {
0220 
0221             const QTransform t = QTransform::fromScale(srcImage->xRes() / dstImage->xRes(),
0222                                                        srcImage->yRes() / dstImage->yRes());
0223 
0224             shapeLayer2->setTransformation(shapeLayer2->transformation() * t);
0225         }
0226 
0227         *node = shapeLayer2;
0228     }
0229 }
0230 
0231 QList<KisNodeSP> KisMimeData::tryLoadInternalNodes(const QMimeData *data,
0232                                                    KisImageSP image,
0233                                                    KisShapeController *shapeController,
0234                                                    bool /* IN-OUT */ &copyNode)
0235 {
0236     QList<KisNodeSP> nodes;
0237     bool forceCopy = false;
0238     KisImageSP sourceImage;
0239 
0240     // Qt 4.7 and Qt 5.5 way
0241     const KisMimeData *mimedata = qobject_cast<const KisMimeData*>(data);
0242     if (mimedata) {
0243         nodes = mimedata->nodes();
0244         forceCopy = mimedata->m_forceCopy;
0245         sourceImage = mimedata->m_image;
0246     }
0247 
0248     // Qt 4.8 way
0249     if (nodes.isEmpty() && data->hasFormat("application/x-krita-node-internal-pointer")) {
0250         QByteArray nodeXml = data->data("application/x-krita-node-internal-pointer");
0251 
0252         QDomDocument doc;
0253         doc.setContent(nodeXml);
0254 
0255         QDomElement element = doc.documentElement();
0256         qint64 pid = element.attribute("application_pid").toLongLong();
0257         forceCopy = element.attribute("force_copy").toInt();
0258         qint64 imagePointerValue = element.attribute("image_pointer_value").toLongLong();
0259         sourceImage = reinterpret_cast<KisImage*>(imagePointerValue);
0260 
0261         if (pid == QApplication::applicationPid()) {
0262 
0263             QDomNode n = element.firstChild();
0264             while (!n.isNull()) {
0265                 QDomElement e = n.toElement();
0266                 if (!e.isNull()) {
0267                     qint64 pointerValue = e.attribute("pointer_value").toLongLong();
0268                     if (pointerValue) {
0269                         nodes << reinterpret_cast<KisNode*>(pointerValue);
0270                     }
0271                 }
0272                 n = n.nextSibling();
0273             }
0274         }
0275     }
0276 
0277     if (!nodes.isEmpty() && (forceCopy || copyNode || sourceImage != image)) {
0278         KisImageBarrierLockerWithFeedbackAllowNull locker(sourceImage);
0279 
0280         QList<KisNodeSP> clones;
0281         Q_FOREACH (KisNodeSP node, nodes) {
0282             node = safeCopyNode(node, sourceImage != image);
0283             if ((forceCopy || copyNode) && sourceImage == image) {
0284                 KisLayerUtils::addCopyOfNameTag(node);
0285             }
0286             initializeExternalNode(&node, sourceImage, image, shapeController);
0287             clones << node;
0288         }
0289         nodes = clones;
0290         copyNode = true;
0291     }
0292     return nodes;
0293 }
0294 
0295 QList<KisNodeSP> KisMimeData::loadNonNativeNodes(const QMimeData *data,
0296                                                 KisImageWSP image,
0297                                                 KisShapeController *shapeController)
0298 {
0299     bool doRecenter = false;
0300     QList<KisNodeSP> nodes;
0301 
0302     if (nodes.isEmpty() && (data->hasFormat("application/x-color") || data->hasFormat("krita/x-colorsetentry"))) {
0303         QColor color = data->hasColor() ? qvariant_cast<QColor>(data->colorData()) : QColor(255, 0, 255);
0304         if (!data->hasColor() && data->hasFormat("krita/x-colorsetentry")) {
0305             QByteArray byteData = data->data("krita/x-colorsetentry");
0306             KisSwatch s = KisSwatch::fromByteArray(byteData);
0307             color = s.color().toQColor();
0308         }
0309         KisGeneratorSP generator = KisGeneratorRegistry::instance()->value("color");
0310         KisFilterConfigurationSP defaultConfig = generator->factoryConfiguration(KisGlobalResourcesInterface::instance());
0311         defaultConfig->setProperty("color", color);
0312         defaultConfig->createLocalResourcesSnapshot(KisGlobalResourcesInterface::instance());
0313 
0314         if (image) {
0315             KisGeneratorLayerSP fillLayer = new KisGeneratorLayer(image, image->nextLayerName(i18n("Fill Layer")),
0316                                                                   defaultConfig, image->globalSelection());
0317             nodes << fillLayer;
0318         }
0319     }
0320 
0321     if (nodes.isEmpty() && data->hasImage()) {
0322         QImage qimage = qvariant_cast<QImage>(data->imageData());
0323 
0324         KisPaintDeviceSP device = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
0325         device->convertFromQImage(qimage, 0);
0326 
0327         if (image) {
0328             nodes << new KisPaintLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8, device);
0329         }
0330 
0331         doRecenter = true;
0332     }
0333 
0334     if (!nodes.isEmpty() && doRecenter) {
0335         const QRect imageBounds = image->bounds();
0336 
0337         Q_FOREACH (KisNodeSP node, nodes) {
0338             const QRect layerBounds = node->projection()->exactBounds();
0339             if (doRecenter) {
0340                 QPoint pt = imageBounds.center() - layerBounds.center();
0341                 node->setX(pt.x());
0342                 node->setY(pt.y());
0343             }
0344         }
0345     }
0346 
0347     return nodes;
0348 }
0349 
0350 QMimeData* KisMimeData::mimeForLayers(const KisNodeList &nodes, KisImageSP image, bool forceCopy)
0351 {
0352     KisNodeList inputNodes = nodes;
0353     KisNodeList sortedNodes;
0354     KisLayerUtils::sortMergableNodes(image->root(), inputNodes, sortedNodes);
0355     if (sortedNodes.isEmpty()) return 0;
0356 
0357     KisMimeData* data = new KisMimeData(sortedNodes, image, forceCopy);
0358     return data;
0359 }
0360 
0361 QMimeData* KisMimeData::mimeForLayersDeepCopy(const KisNodeList &nodes, KisImageSP image, bool forceCopy)
0362 {
0363     KisNodeList inputNodes = nodes;
0364     KisNodeList sortedNodes;
0365     KisLayerUtils::sortMergableNodes(image->root(), inputNodes, sortedNodes);
0366     if (sortedNodes.isEmpty()) return 0;
0367 
0368     KisMimeData* data = new KisMimeData(sortedNodes, image, forceCopy);
0369     data->deepCopyNodes();
0370     return data;
0371 }
0372 
0373 bool nodeAllowsAsChild(KisNodeSP parent, KisNodeList nodes)
0374 {
0375     bool result = true;
0376     Q_FOREACH (KisNodeSP node, nodes) {
0377         if (!parent->allowAsChild(node) || !parent->isEditable(false)) {
0378             result = false;
0379             break;
0380         }
0381     }
0382     return result;
0383 }
0384 
0385 bool correctNewNodeLocation(KisNodeList nodes,
0386                             KisNodeDummy* &parentDummy,
0387                             KisNodeDummy* &aboveThisDummy)
0388 {
0389     KisNodeSP parentNode = parentDummy->node();
0390     bool result = true;
0391 
0392     if(!nodeAllowsAsChild(parentDummy->node(), nodes) ||
0393             (parentDummy->node()->inherits("KisGroupLayer") && parentDummy->node()->collapsed())) {
0394         aboveThisDummy = parentDummy;
0395         parentDummy = parentDummy->parent();
0396 
0397         result = (!parentDummy) ? false :
0398             correctNewNodeLocation(nodes, parentDummy, aboveThisDummy);
0399     }
0400 
0401     return result;
0402 }
0403 
0404 KisNodeList KisMimeData::loadNodesFast(
0405     const QMimeData *data,
0406     KisImageSP image,
0407     KisShapeController *shapeController,
0408     bool &copyNode)
0409 {
0410     QList<KisNodeSP> nodes =
0411         KisMimeData::tryLoadInternalNodes(data,
0412                                           image,
0413                                           shapeController,
0414                                           copyNode /* IN-OUT */);
0415 
0416     if (nodes.isEmpty()) {
0417         nodes = KisMimeData::loadNonNativeNodes(data, image, shapeController);
0418         /**
0419          * Don't try to move a node originating from another image,
0420          * just copy it.
0421          */
0422         copyNode = true;
0423     }
0424 
0425     return nodes;
0426 }
0427 
0428 KisNodeList KisMimeData::loadNodesFastAndRecenter(const QPoint &preferredCenter, const QMimeData *data, KisImageSP image, KisShapeController *shapeController, bool &copyNode)
0429 {
0430     KisNodeList nodes = loadNodesFast(data, image, shapeController, copyNode);
0431 
0432     Q_FOREACH (KisNodeSP node, nodes) {
0433         const QRect layerBounds = node->exactBounds();
0434         const QPoint offset = preferredCenter - layerBounds.center();
0435 
0436         node->setX(node->x() + offset.x());
0437         node->setY(node->y() + offset.y());
0438     }
0439 
0440     return nodes;
0441 }
0442 
0443 bool KisMimeData::insertMimeLayers(const QMimeData *data,
0444                                    KisImageSP image,
0445                                    KisShapeController *shapeController,
0446                                    KisNodeDummy *parentDummy,
0447                                    KisNodeDummy *aboveThisDummy,
0448                                    bool copyNode,
0449                                    KisNodeInsertionAdapter *nodeInsertionAdapter,
0450                                    bool changeOffset,
0451                                    QPointF offset)
0452 {
0453     QList<KisNodeSP> nodes = loadNodesFast(data, image, shapeController, copyNode /* IN-OUT */);
0454 
0455     if (changeOffset) {
0456         Q_FOREACH (KisNodeSP node, nodes) {
0457             KisLayerUtils::recursiveApplyNodes(node, [offset] (KisNodeSP node){
0458                 if (node->hasEditablePaintDevice()) {
0459                     KisPaintDeviceSP dev = node->paintDevice();
0460                     dev->moveTo(offset.x(), offset.y());
0461                 }
0462             });
0463         }
0464     }
0465 
0466     if (nodes.isEmpty()) return false;
0467 
0468     bool result = true;
0469 
0470     if (!correctNewNodeLocation(nodes, parentDummy, aboveThisDummy)) {
0471         return false;
0472     }
0473 
0474     KIS_ASSERT_RECOVER(nodeInsertionAdapter) { return false; }
0475 
0476     Q_ASSERT(parentDummy);
0477     KisNodeSP aboveThisNode = aboveThisDummy ? aboveThisDummy->node() : 0;
0478     if (copyNode) {
0479         nodeInsertionAdapter->addNodes(nodes, parentDummy->node(), aboveThisNode);
0480     }
0481     else {
0482         Q_ASSERT(nodes.first()->graphListener() == image.data());
0483         nodeInsertionAdapter->moveNodes(nodes, parentDummy->node(), aboveThisNode);
0484     }
0485 
0486     const bool hasDelayedNodes =
0487         std::find_if(nodes.begin(), nodes.end(),
0488                      [] (KisNodeSP node) {
0489                          return bool(dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data()));
0490                      }) != nodes.end();
0491 
0492     if (hasDelayedNodes) {
0493         /**
0494          * We have the node juggler running, so it will delay the update of the
0495          * generator layers that might be included into the paste. To avoid
0496          * that we should forcefully to make it stop
0497          */
0498         image->requestStrokeEnd();
0499     }
0500 
0501     return result;
0502 }