File indexing completed on 2024-12-22 04:10:08
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_multiple_projection.h" 0008 0009 #include <QMap> 0010 #include <QReadWriteLock> 0011 0012 0013 #include <KoColorSpace.h> 0014 0015 #include "kis_painter.h" 0016 #include "kis_paint_device.h" 0017 #include "kis_layer_style_filter_environment.h" 0018 0019 0020 struct ProjectionStruct { 0021 KisPaintDeviceSP device; 0022 QString compositeOpId; 0023 quint8 opacity = OPACITY_OPAQUE_U8; 0024 QBitArray channelFlags; 0025 }; 0026 0027 typedef QMap<QString, ProjectionStruct> PlanesMap; 0028 0029 struct KisMultipleProjection::Private 0030 { 0031 QReadWriteLock lock; 0032 PlanesMap planes; 0033 }; 0034 0035 0036 KisMultipleProjection::KisMultipleProjection() 0037 : m_d(new Private) 0038 { 0039 } 0040 0041 KisMultipleProjection::KisMultipleProjection(const KisMultipleProjection &rhs) 0042 : m_d(new Private) 0043 { 0044 QReadLocker readLocker(&rhs.m_d->lock); 0045 0046 auto it = rhs.m_d->planes.constBegin(); 0047 for (; it != rhs.m_d->planes.constEnd(); ++it) { 0048 ProjectionStruct proj; 0049 proj.device = new KisPaintDevice(*it->device); 0050 proj.compositeOpId = it->compositeOpId; 0051 proj.opacity = it->opacity; 0052 proj.channelFlags = it->channelFlags; 0053 0054 m_d->planes.insert(it.key(), proj); 0055 } 0056 } 0057 0058 KisMultipleProjection::~KisMultipleProjection() 0059 { 0060 } 0061 0062 QString KisMultipleProjection::defaultProjectionId() 0063 { 0064 return "00_default"; 0065 } 0066 0067 KisPaintDeviceSP KisMultipleProjection::getProjection(const QString &id, 0068 const QString &compositeOpId, 0069 quint8 opacity, 0070 const QBitArray &channelFlags, 0071 KisPaintDeviceSP prototype) 0072 { 0073 QReadLocker readLocker(&m_d->lock); 0074 0075 PlanesMap::const_iterator constIt = m_d->planes.constFind(id); 0076 0077 if (constIt == m_d->planes.constEnd() || 0078 constIt->compositeOpId != compositeOpId || 0079 constIt->opacity != opacity || 0080 constIt->channelFlags != channelFlags || 0081 *constIt->device->colorSpace() != *prototype->colorSpace()) { 0082 0083 readLocker.unlock(); 0084 0085 { 0086 QWriteLocker writeLocker(&m_d->lock); 0087 0088 PlanesMap::iterator writeIt = m_d->planes.find(id); 0089 if (writeIt == m_d->planes.end()) { 0090 ProjectionStruct plane; 0091 plane.device = new KisPaintDevice(prototype->colorSpace()); 0092 plane.device->prepareClone(prototype); 0093 plane.compositeOpId = compositeOpId; 0094 plane.opacity = opacity; 0095 plane.channelFlags = channelFlags; 0096 writeIt = m_d->planes.insert(id, plane); 0097 } else if (writeIt->compositeOpId != compositeOpId || 0098 *writeIt->device->colorSpace() != *prototype->colorSpace()) { 0099 0100 writeIt->device->prepareClone(prototype); 0101 writeIt->compositeOpId = compositeOpId; 0102 writeIt->opacity = opacity; 0103 writeIt->channelFlags = channelFlags; 0104 } 0105 0106 return writeIt->device; 0107 } 0108 } 0109 0110 return constIt->device; 0111 } 0112 0113 void KisMultipleProjection::freeProjection(const QString &id) 0114 { 0115 QWriteLocker writeLocker(&m_d->lock); 0116 m_d->planes.remove(id); 0117 } 0118 0119 void KisMultipleProjection::freeAllProjections() 0120 { 0121 QWriteLocker writeLocker(&m_d->lock); 0122 m_d->planes.clear(); 0123 } 0124 0125 void KisMultipleProjection::clear(const QRect &rc) 0126 { 0127 QReadLocker readLocker(&m_d->lock); 0128 0129 PlanesMap::const_iterator it = m_d->planes.constBegin(); 0130 PlanesMap::const_iterator end = m_d->planes.constEnd(); 0131 0132 for (; it != end; ++it) { 0133 const_cast<KisPaintDevice*>(it->device.data())->clear(rc); 0134 } 0135 } 0136 0137 void KisMultipleProjection::apply(KisPaintDeviceSP dstDevice, const QRect &rect, KisLayerStyleFilterEnvironment *env) 0138 { 0139 QReadLocker readLocker(&m_d->lock); 0140 0141 PlanesMap::const_iterator it = m_d->planes.constBegin(); 0142 PlanesMap::const_iterator end = m_d->planes.constEnd(); 0143 0144 for (; it != end; ++it) { 0145 KisPainter gc(dstDevice); 0146 gc.setCompositeOpId(it->compositeOpId); 0147 env->setupFinalPainter(&gc, it->opacity, it->channelFlags); 0148 gc.bitBlt(rect.topLeft(), it->device, rect); 0149 } 0150 } 0151 0152 KisPaintDeviceList KisMultipleProjection::getLodCapableDevices() const 0153 { 0154 QReadLocker readLocker(&m_d->lock); 0155 0156 PlanesMap::const_iterator it = m_d->planes.constBegin(); 0157 PlanesMap::const_iterator end = m_d->planes.constEnd(); 0158 0159 KisPaintDeviceList list; 0160 for (; it != end; ++it) { 0161 list << it->device; 0162 } 0163 0164 return list; 0165 } 0166 0167 bool KisMultipleProjection::isEmpty() const 0168 { 0169 return m_d->planes.isEmpty(); 0170 } 0171