File indexing completed on 2024-05-12 15:58:24
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_layer_projection_plane.h" 0008 0009 #include <QBitArray> 0010 #include <KoColorSpace.h> 0011 #include <KoChannelInfo.h> 0012 #include <KoCompositeOpRegistry.h> 0013 #include "kis_painter.h" 0014 #include "kis_projection_leaf.h" 0015 #include "kis_cached_paint_device.h" 0016 #include "kis_sequential_iterator.h" 0017 0018 0019 struct KisLayerProjectionPlane::Private 0020 { 0021 KisLayer *layer; 0022 KisCachedPaintDevice cachedDevice; 0023 }; 0024 0025 0026 KisLayerProjectionPlane::KisLayerProjectionPlane(KisLayer *layer) 0027 : m_d(new Private) 0028 { 0029 m_d->layer = layer; 0030 } 0031 0032 KisLayerProjectionPlane::~KisLayerProjectionPlane() 0033 { 0034 } 0035 0036 QRect KisLayerProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode) 0037 { 0038 return m_d->layer->updateProjection(rect, filthyNode); 0039 } 0040 0041 void KisLayerProjectionPlane::applyImpl(KisPainter *painter, const QRect &rect, KritaUtils::ThresholdMode thresholdMode) 0042 { 0043 KisPaintDeviceSP device = m_d->layer->projection(); 0044 if (!device) return; 0045 0046 QRect needRect = rect; 0047 0048 if (m_d->layer->compositeOpId() != COMPOSITE_COPY && 0049 m_d->layer->compositeOpId() != COMPOSITE_DESTINATION_IN && 0050 m_d->layer->compositeOpId() != COMPOSITE_DESTINATION_ATOP) { 0051 0052 needRect &= device->extent(); 0053 } 0054 0055 if(needRect.isEmpty()) return; 0056 0057 QBitArray channelFlags = m_d->layer->projectionLeaf()->channelFlags(); 0058 0059 0060 // if the color spaces don't match we will have a problem with the channel flags 0061 // because the channel flags from the source layer doesn't match with the colorspace of the projection device 0062 // this leads to the situation that the wrong channels will be enabled/disabled 0063 const KoColorSpace* srcCS = device->colorSpace(); 0064 const KoColorSpace* dstCS = painter->device()->colorSpace(); 0065 0066 if (!channelFlags.isEmpty() && srcCS != dstCS) { 0067 bool alphaFlagIsSet = (srcCS->channelFlags(false,true) & channelFlags) == srcCS->channelFlags(false,true); 0068 bool allColorFlagsAreSet = (srcCS->channelFlags(true,false) & channelFlags) == srcCS->channelFlags(true,false); 0069 bool allColorFlagsAreUnset = (srcCS->channelFlags(true,false) & channelFlags).count(true) == 0; 0070 0071 if(allColorFlagsAreSet) { 0072 channelFlags = dstCS->channelFlags(true, alphaFlagIsSet); 0073 } else if(allColorFlagsAreUnset) { 0074 channelFlags = dstCS->channelFlags(false, alphaFlagIsSet); 0075 } else { 0076 //TODO: convert the cannel flags properly 0077 // for now just the alpha channel bit is copied and the other channels are left alone 0078 for (quint32 i=0; i < dstCS->channelCount(); ++i) { 0079 if (dstCS->channels()[i]->channelType() == KoChannelInfo::ALPHA) { 0080 channelFlags.setBit(i, alphaFlagIsSet); 0081 break; 0082 } 0083 } 0084 } 0085 } 0086 0087 QScopedPointer<KisCachedPaintDevice::Guard> d1; 0088 0089 if (thresholdMode != KritaUtils::ThresholdNone) { 0090 d1.reset(new KisCachedPaintDevice::Guard(device, m_d->cachedDevice)); 0091 KisPaintDeviceSP tmp = d1->device(); 0092 tmp->makeCloneFromRough(device, needRect); 0093 0094 KritaUtils::thresholdOpacity(tmp, needRect, thresholdMode); 0095 0096 device = tmp; 0097 } 0098 0099 painter->setChannelFlags(channelFlags); 0100 painter->setCompositeOpId(m_d->layer->compositeOpId()); 0101 painter->setOpacity(m_d->layer->projectionLeaf()->opacity()); 0102 painter->bitBlt(needRect.topLeft(), device, needRect); 0103 } 0104 0105 void KisLayerProjectionPlane::apply(KisPainter *painter, const QRect &rect) 0106 { 0107 applyImpl(painter, rect, KritaUtils::ThresholdNone); 0108 } 0109 0110 void KisLayerProjectionPlane::applyMaxOutAlpha(KisPainter *painter, const QRect &rect, KritaUtils::ThresholdMode thresholdMode) 0111 { 0112 applyImpl(painter, rect, thresholdMode); 0113 } 0114 0115 KisPaintDeviceList KisLayerProjectionPlane::getLodCapableDevices() const 0116 { 0117 return KisPaintDeviceList() << m_d->layer->projection(); 0118 } 0119 0120 QRect KisLayerProjectionPlane::needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const 0121 { 0122 return m_d->layer->needRect(rect, pos); 0123 } 0124 0125 QRect KisLayerProjectionPlane::changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const 0126 { 0127 return m_d->layer->changeRect(rect, pos); 0128 } 0129 0130 QRect KisLayerProjectionPlane::accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const 0131 { 0132 return m_d->layer->accessRect(rect, pos); 0133 } 0134 0135 QRect KisLayerProjectionPlane::needRectForOriginal(const QRect &rect) const 0136 { 0137 return m_d->layer->needRectForOriginal(rect); 0138 } 0139 0140 QRect KisLayerProjectionPlane::tightUserVisibleBounds() const 0141 { 0142 return m_d->layer->tightUserVisibleBounds(); 0143 } 0144