diff --git a/libs/image/kis_clone_layer.cpp b/libs/image/kis_clone_layer.cpp index 6f1ec35f69..7ae7424dc9 100644 --- a/libs/image/kis_clone_layer.cpp +++ b/libs/image/kis_clone_layer.cpp @@ -1,327 +1,337 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_clone_layer.h" #include #include #include #include #include #include #include "kis_default_bounds.h" #include "kis_paint_device.h" #include "kis_image.h" #include "kis_painter.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" #include "kis_paint_layer.h" #include #include #include "kis_lod_capable_layer_offset.h" struct Q_DECL_HIDDEN KisCloneLayer::Private { Private(KisDefaultBoundsBaseSP defaultBounds) : offset(defaultBounds) { } KisPaintDeviceSP fallback; KisLodCapableLayerOffset offset; KisLayerSP copyFrom; KisNodeUuidInfo copyFromInfo; CopyLayerType type; }; KisCloneLayer::KisCloneLayer(KisLayerSP from, KisImageWSP image, const QString &name, quint8 opacity) : KisLayer(image, name, opacity) , m_d(new Private(new KisDefaultBounds(image))) { KisImageSP imageSP = image.toStrongRef(); if (!imageSP) { return; } - m_d->fallback = new KisPaintDevice(imageSP->colorSpace()); + m_d->fallback = new KisPaintDevice(this, + imageSP->colorSpace(), + new KisDefaultBounds(imageSP)); m_d->copyFrom = from; m_d->type = COPY_PROJECTION; // When loading the layer we copy from might not exist yet if (m_d->copyFrom) { m_d->copyFrom->registerClone(this); } } KisCloneLayer::KisCloneLayer(const KisCloneLayer& rhs) : KisLayer(rhs) , m_d(new Private(new KisDefaultBounds(rhs.image()))) { - m_d->fallback = new KisPaintDevice(rhs.m_d->fallback->colorSpace()); + m_d->fallback = new KisPaintDevice(this, + rhs.m_d->fallback->colorSpace(), + new KisDefaultBounds(rhs.image())); m_d->copyFrom = rhs.copyFrom(); m_d->type = rhs.copyType(); m_d->offset = rhs.m_d->offset; if (m_d->copyFrom) { m_d->copyFrom->registerClone(this); } } KisCloneLayer::~KisCloneLayer() { if (m_d->copyFrom) { m_d->copyFrom->unregisterClone(this); } delete m_d; } KisLayerSP KisCloneLayer::reincarnateAsPaintLayer() const { KisPaintDeviceSP newOriginal = new KisPaintDevice(*original()); KisPaintLayerSP newLayer = new KisPaintLayer(image(), name(), opacity(), newOriginal); newLayer->setX(newLayer->x() + x()); newLayer->setY(newLayer->y() + y()); newLayer->setCompositeOpId(compositeOpId()); newLayer->mergeNodeProperties(nodeProperties()); return newLayer; } +void KisCloneLayer::setImage(KisImageWSP image) +{ + m_d->fallback->setDefaultBounds(new KisDefaultBounds(image)); + KisLayer::setImage(image); +} + bool KisCloneLayer::allowAsChild(KisNodeSP node) const { return node->inherits("KisMask"); } KisPaintDeviceSP KisCloneLayer::paintDevice() const { return 0; } KisPaintDeviceSP KisCloneLayer::original() const { if (!m_d->copyFrom || !m_d->copyFrom->projection()) return m_d->fallback; KisPaintDeviceSP retval; switch (m_d->type) { case COPY_PROJECTION: retval = m_d->copyFrom->projection(); break; case COPY_ORIGINAL: default: retval = m_d->copyFrom->original(); } return retval; } bool KisCloneLayer::needProjection() const { return m_d->offset.x() || m_d->offset.y(); } void KisCloneLayer::copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect& rect) const { QRect copyRect = rect; copyRect.translate(-m_d->offset.x(), -m_d->offset.y()); KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, copyRect); } void KisCloneLayer::setDirtyOriginal(const QRect &rect) { /** * The original will be updated when the clone becomes visible * again. */ if (!visible(true)) return; /** * HINT: this method is present for historical reasons only. * Long time ago the updates were calculated in * "copyOriginalToProjection" coordinate system. Now * everything is done in "original()" space. */ KisLayer::setDirty(rect); } void KisCloneLayer::notifyParentVisibilityChanged(bool value) { KisImageSP imageSP = image().toStrongRef(); if (!imageSP) { return; } KisLayer::setDirty(imageSP->bounds()); KisLayer::notifyParentVisibilityChanged(value); } QRect KisCloneLayer::needRectOnSourceForMasks(const QRect &rc) const { QStack applyRects_unused; bool rectVariesFlag; QList effectMasks = this->effectMasks(); if (effectMasks.isEmpty()) return QRect(); QRect needRect = this->masksNeedRect(effectMasks, rc, applyRects_unused, rectVariesFlag); if (needRect.isEmpty() || (!rectVariesFlag && needRect == rc)) { return QRect(); } return needRect; } qint32 KisCloneLayer::x() const { return m_d->offset.x(); } qint32 KisCloneLayer::y() const { return m_d->offset.y(); } void KisCloneLayer::setX(qint32 x) { m_d->offset.setX(x); } void KisCloneLayer::setY(qint32 y) { m_d->offset.setY(y); } QRect KisCloneLayer::extent() const { QRect rect = original()->extent(); // HINT: no offset now. See a comment in setDirtyOriginal() return rect | projection()->extent(); } QRect KisCloneLayer::exactBounds() const { QRect rect = original()->exactBounds(); // HINT: no offset now. See a comment in setDirtyOriginal() return rect | projection()->exactBounds(); } QRect KisCloneLayer::accessRect(const QRect &rect, PositionToFilthy pos) const { QRect resultRect = rect; if(pos & (N_FILTHY_PROJECTION | N_FILTHY)) { if (m_d->offset.x() || m_d->offset.y()) { resultRect |= rect.translated(-m_d->offset.x(), -m_d->offset.y()); } /** * KisUpdateOriginalVisitor will try to recalculate some area * on the clone's source, so this extra rectangle should also * be taken into account */ resultRect |= needRectOnSourceForMasks(rect); } return resultRect; } QRect KisCloneLayer::outgoingChangeRect(const QRect &rect) const { return rect.translated(m_d->offset.x(), m_d->offset.y()); } bool KisCloneLayer::accept(KisNodeVisitor & v) { return v.visit(this); } void KisCloneLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { return visitor.visit(this, undoAdapter); } void KisCloneLayer::setCopyFrom(KisLayerSP fromLayer) { if (m_d->copyFrom) { m_d->copyFrom->unregisterClone(this); } m_d->copyFrom = fromLayer; if (m_d->copyFrom) { m_d->copyFrom->registerClone(this); } } KisLayerSP KisCloneLayer::copyFrom() const { return m_d->copyFrom; } void KisCloneLayer::setCopyType(CopyLayerType type) { m_d->type = type; } CopyLayerType KisCloneLayer::copyType() const { return m_d->type; } KisNodeUuidInfo KisCloneLayer::copyFromInfo() const { return m_d->copyFrom ? KisNodeUuidInfo(m_d->copyFrom) : m_d->copyFromInfo; } void KisCloneLayer::setCopyFromInfo(KisNodeUuidInfo info) { Q_ASSERT(!m_d->copyFrom); m_d->copyFromInfo = info; } QIcon KisCloneLayer::icon() const { return KisIconUtils::loadIcon("cloneLayer"); } KisBaseNode::PropertyList KisCloneLayer::sectionModelProperties() const { KisBaseNode::PropertyList l = KisLayer::sectionModelProperties(); if (m_d->copyFrom) l << KisBaseNode::Property(KoID("copy_from", i18n("Copy From")), m_d->copyFrom->name()); return l; } void KisCloneLayer::syncLodCache() { KisLayer::syncLodCache(); m_d->offset.syncLodOffset(); } diff --git a/libs/image/kis_clone_layer.h b/libs/image/kis_clone_layer.h index 785099684c..60e8ebf3bd 100644 --- a/libs/image/kis_clone_layer.h +++ b/libs/image/kis_clone_layer.h @@ -1,135 +1,137 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_CLONE_LAYER_H_ #define KIS_CLONE_LAYER_H_ #include #include "kis_types.h" #include "kis_layer.h" #include #include "kis_node_uuid_info.h" class KisNodeVisitor; enum CopyLayerType { COPY_PROJECTION, COPY_ORIGINAL }; /** * A copy layer adds the contents of another layer in another place in * the layer stack. It is possible to add more effect masks to the * copy. You can either copy the original data or the projection data * produced by the original layer + original effect masks. There is no * physical copy of the data; if the original changes, the copy * changes too. The copy layer can be positioned differently from the * original layer. **/ class KRITAIMAGE_EXPORT KisCloneLayer : public KisLayer { Q_OBJECT public: KisCloneLayer(KisLayerSP from, KisImageWSP image, const QString &name, quint8 opacity); KisCloneLayer(const KisCloneLayer& rhs); ~KisCloneLayer() override; KisNodeSP clone() const override { return KisNodeSP(new KisCloneLayer(*this)); } /** * When the source layer of the clone is removed from the stack * we should substitute the clone with a usual paint layer, * because the source might become unreachable quite soon. This * method builds a paint layer representation of this clone. */ KisLayerSP reincarnateAsPaintLayer() const; + void setImage(KisImageWSP image) override; + bool allowAsChild(KisNodeSP) const override; KisPaintDeviceSP original() const override; KisPaintDeviceSP paintDevice() const override; bool needProjection() const override; QIcon icon() const override; KisBaseNode::PropertyList sectionModelProperties() const override; qint32 x() const override; qint32 y() const override; void setX(qint32) override; void setY(qint32) override; /// Returns an approximation of where the bounds on actual data are in this layer QRect extent() const override; /// Returns the exact bounds of where the actual data resides in this layer QRect exactBounds() const override; bool accept(KisNodeVisitor &) override; void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) override; /** * Used when loading: loading is done in two passes, and the copy * from layer is set when all layers have been created, not during * loading. */ void setCopyFromInfo(KisNodeUuidInfo info); KisNodeUuidInfo copyFromInfo() const; void setCopyFrom(KisLayerSP layer); KisLayerSP copyFrom() const; void setCopyType(CopyLayerType type); CopyLayerType copyType() const; /** * This function is called by the original to notify * us that it is dirty */ void setDirtyOriginal(const QRect &rect); QRect needRectOnSourceForMasks(const QRect &rc) const; void syncLodCache() override; protected: // override from KisNode QRect accessRect(const QRect &rect, PositionToFilthy pos) const override; // override from KisLayer void copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect& rect) const override; void notifyParentVisibilityChanged(bool value) override; QRect outgoingChangeRect(const QRect &rect) const override; private: struct Private; Private * const m_d; }; #endif // KIS_CLONE_LAYER_H_