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