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_ */