File indexing completed on 2024-05-12 15:58:22

0001 /*
0002  *  SPDX-FileCopyrightText: 2004 Bart Coppens <kde@bartcoppens.be>
0003  *  SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #ifndef KIS_INDIRECT_PAINTING_SUPPORT_H_
0009 #define KIS_INDIRECT_PAINTING_SUPPORT_H_
0010 
0011 #include "kritaimage_export.h"
0012 #include "kis_types.h"
0013 
0014 #include <mutex>
0015 
0016 class QBitArray;
0017 class KisUndoAdapter;
0018 class KisPostExecutionUndoAdapter;
0019 class KisPainter;
0020 class KUndo2MagicString;
0021 class KoCompositeOp;
0022 class KoColor;
0023 class KisRunnableStrokeJobData;
0024 
0025 /**
0026  * For classes that support indirect painting.
0027  *
0028  * XXX: Name doesn't suggest an object -- is KisIndirectPaintingLayer
0029  * a better name? (BSAR)
0030  */
0031 class KRITAIMAGE_EXPORT KisIndirectPaintingSupport
0032 {
0033     KisIndirectPaintingSupport(const KisIndirectPaintingSupport&);
0034     KisIndirectPaintingSupport& operator=(const KisIndirectPaintingSupport&);
0035 public:
0036 
0037     KisIndirectPaintingSupport();
0038     virtual ~KisIndirectPaintingSupport();
0039 
0040     bool hasTemporaryTarget() const;
0041 
0042     virtual void setCurrentColor(const KoColor &color);
0043     void setTemporaryTarget(KisPaintDeviceSP t);
0044     void setTemporaryCompositeOp(const QString &id);
0045     void setTemporaryOpacity(quint8 o);
0046     void setTemporaryChannelFlags(const QBitArray& channelFlags);
0047     void setTemporarySelection(KisSelectionSP selection);
0048 
0049     /**
0050      * Configures the painter to conform the painting parameters
0051      * stored for th temporary target, such as compositeOp, opacity,
0052      * channel flags and selection. Please do not setup them manually,
0053      * but use this function instead.
0054      */
0055     void setupTemporaryPainter(KisPainter *painter) const;
0056 
0057     /**
0058      * Writes the temporary target into the paint device of the layer.
0059      * This action will lock the temporary target itself.
0060      */
0061     void mergeToLayer(KisNodeSP layer, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID);
0062     virtual void mergeToLayerThreaded(KisNodeSP layer, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID, QVector<KisRunnableStrokeJobData *> *jobs);
0063 
0064     KisPaintDeviceSP temporaryTarget() const;
0065 
0066     virtual bool supportsNonIndirectPainting() const;
0067 
0068     /**
0069      * A guard object to lock the temporary target for read
0070      */
0071     struct ReadLocker {
0072         ReadLocker(const KisIndirectPaintingSupport *lock) : m_lock(lock) {
0073             m_lock->lockTemporaryTarget();
0074         }
0075         ~ReadLocker() {
0076             m_lock->unlockTemporaryTarget();
0077         }
0078 
0079     private:
0080         const KisIndirectPaintingSupport *m_lock;
0081     };
0082 
0083     /**
0084      * A simple RAII-styled class to release the write lock for the
0085      * final merge while the stroke is suspended.
0086      */
0087     struct FinalMergeSuspender {
0088         FinalMergeSuspender(KisIndirectPaintingSupport *indirect);
0089         ~FinalMergeSuspender();
0090 
0091     private:
0092         const KisIndirectPaintingSupport *m_lock;
0093     };
0094     using FinalMergeSuspenderSP = QSharedPointer<FinalMergeSuspender>;
0095 
0096     /**
0097      * When the stroke uses multithreaded final merge and supports
0098      * suspension, then it should also suspend the final merge explicitly
0099      * by requesting a special RAII object for the whole period of
0100      * suspension.
0101      */
0102     FinalMergeSuspenderSP trySuspendFinalMerge();
0103 
0104 protected:
0105     /**
0106      * A guard object to lock the temporary target for write
0107      */
0108     struct WriteLocker {
0109         WriteLocker(KisIndirectPaintingSupport *lock)
0110             : m_lock(lock),
0111               m_locked(true)
0112         {
0113             m_lock->lockTemporaryTargetForWrite();
0114         }
0115 
0116         WriteLocker(KisIndirectPaintingSupport *lock, std::defer_lock_t)
0117             : m_lock(lock),
0118               m_locked(false)
0119         {
0120         }
0121 
0122         ~WriteLocker() {
0123             if (m_locked) {
0124                 m_lock->unlockTemporaryTarget();
0125             }
0126         }
0127 
0128         void unlock() {
0129             KIS_SAFE_ASSERT_RECOVER_RETURN(m_locked);
0130             m_lock->unlockTemporaryTarget();
0131             m_locked = false;
0132         }
0133 
0134         void relock() {
0135             KIS_SAFE_ASSERT_RECOVER_RETURN(!m_locked);
0136             m_lock->lockTemporaryTargetForWrite();
0137             m_locked = true;
0138         }
0139 
0140         bool isLocked() {
0141             return m_locked;
0142         }
0143 
0144     private:
0145         KisIndirectPaintingSupport *m_lock;
0146         bool m_locked = false;
0147     };
0148 
0149     using WriteLockerSP = QSharedPointer<WriteLocker>;
0150 
0151     void mergeToLayerImpl(KisPaintDeviceSP dst, KUndo2Command *parentCommand, const KUndo2MagicString &transactionText, int timedID, bool cleanResources, WriteLockerSP sharedWriteLock, QVector<KisRunnableStrokeJobData *> *jobs);
0152     virtual void writeMergeData(KisPainter *painter, KisPaintDeviceSP src, const QRect &rc);
0153     void lockTemporaryTargetForWrite() const;
0154 
0155     QString temporaryCompositeOp() const;
0156     void releaseResources();
0157 
0158 private:
0159     /**
0160      * Lock the temporary target.
0161      * It should be done for guarding every access to
0162      * temporaryTarget() or original()
0163      * NOTE: well, not "every", but...
0164      */
0165     void lockTemporaryTarget() const;
0166 
0167     /**
0168      * Unlock the temporary target
0169      *
0170      * \see lockTemporaryTarget()
0171      */
0172     void unlockTemporaryTarget() const;
0173 
0174 private:
0175     friend class KisPainterBasedStrokeStrategy;
0176 
0177     /**
0178      * Only for debugging purposes. Please use setupTemporaryPainer()
0179      * instead.
0180      */
0181     KisSelectionSP temporarySelection() const;
0182 
0183 private:
0184     struct Private;
0185     Private* const d;
0186 };
0187 
0188 
0189 #endif /* KIS_INDIRECT_PAINTING_SUPPORT_H_ */