File indexing completed on 2024-05-19 04:28:59

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