File indexing completed on 2024-05-12 15:58:15
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include <KoIcon.h> 0008 #include <kis_icon.h> 0009 #include <KoCompositeOpRegistry.h> 0010 0011 #include "kis_layer.h" 0012 #include "kis_filter_mask.h" 0013 #include "filter/kis_filter.h" 0014 #include "filter/kis_filter_configuration.h" 0015 #include "filter/kis_filter_registry.h" 0016 #include "kis_selection.h" 0017 #include "kis_processing_information.h" 0018 #include "kis_node.h" 0019 #include "kis_node_visitor.h" 0020 #include "kis_processing_visitor.h" 0021 #include "kis_busy_progress_indicator.h" 0022 #include "kis_transaction.h" 0023 #include "kis_painter.h" 0024 0025 KisFilterMask::KisFilterMask(KisImageWSP image, const QString &name) 0026 : KisEffectMask(image, name), 0027 KisNodeFilterInterface(0) 0028 { 0029 setCompositeOpId(COMPOSITE_COPY); 0030 } 0031 0032 KisFilterMask::~KisFilterMask() 0033 { 0034 } 0035 0036 KisFilterMask::KisFilterMask(const KisFilterMask& rhs) 0037 : KisEffectMask(rhs) 0038 , KisNodeFilterInterface(rhs) 0039 { 0040 } 0041 0042 QIcon KisFilterMask::icon() const 0043 { 0044 return KisIconUtils::loadIcon("filterMask"); 0045 } 0046 0047 void KisFilterMask::setFilter(KisFilterConfigurationSP filterConfig, bool checkCompareConfig) 0048 { 0049 KisNodeFilterInterface::setFilter(filterConfig, checkCompareConfig); 0050 } 0051 0052 QRect KisFilterMask::decorateRect(KisPaintDeviceSP &src, 0053 KisPaintDeviceSP &dst, 0054 const QRect & rc, 0055 PositionToFilthy maskPos) const 0056 { 0057 Q_UNUSED(maskPos); 0058 0059 KisFilterConfigurationSP filterConfig = filter(); 0060 0061 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(nodeProgressProxy(), rc); 0062 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE( 0063 src != dst && 0064 "KisFilterMask::decorateRect: " 0065 "src must be != dst, because we can't create transactions " 0066 "during merge, as it breaks reentrancy", 0067 rc); 0068 0069 if (!filterConfig) { 0070 return QRect(); 0071 } 0072 0073 KisFilterSP filter = 0074 KisFilterRegistry::instance()->value(filterConfig->name()); 0075 0076 if (!filter) { 0077 warnKrita << "Could not retrieve filter \"" << filterConfig->name() << "\""; 0078 return QRect(); 0079 } 0080 0081 KIS_ASSERT_RECOVER_NOOP(this->busyProgressIndicator()); 0082 this->busyProgressIndicator()->update(); 0083 0084 filter->process(src, dst, 0, rc, filterConfig.data(), 0); 0085 0086 QRect r = filter->changedRect(rc, filterConfig.data(), dst->defaultBounds()->currentLevelOfDetail()); 0087 return r; 0088 } 0089 0090 bool KisFilterMask::accept(KisNodeVisitor &v) 0091 { 0092 return v.visit(this); 0093 } 0094 0095 void KisFilterMask::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) 0096 { 0097 return visitor.visit(this, undoAdapter); 0098 } 0099 0100 /** 0101 * FIXME: try to cache filter pointer inside a Private block 0102 */ 0103 QRect KisFilterMask::changeRect(const QRect &rect, PositionToFilthy pos) const 0104 { 0105 /** 0106 * FIXME: This check of the emptiness should be done 0107 * on the higher/lower level 0108 */ 0109 if(rect.isEmpty()) return rect; 0110 0111 QRect filteredRect = rect; 0112 0113 KisFilterConfigurationSP filterConfig = filter(); 0114 if (filterConfig) { 0115 KisNodeSP parent = this->parent(); 0116 const int lod = parent && parent->projection() ? 0117 parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; 0118 0119 KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); 0120 filteredRect = filter->changedRect(rect, filterConfig.data(), lod); 0121 } 0122 0123 /** 0124 * We can't paint outside a selection, that is why we call 0125 * KisMask::changeRect to crop actual change area in the end 0126 */ 0127 filteredRect = KisMask::changeRect(filteredRect, pos); 0128 /** 0129 * FIXME: Think over this solution 0130 * Union of rects means that changeRect returns NOT the rect 0131 * changed by this very layer, but an accumulated rect changed 0132 * by all underlying layers. Just take into account and change 0133 * documentation accordingly 0134 */ 0135 return rect | filteredRect; 0136 } 0137 0138 QRect KisFilterMask::needRect(const QRect& rect, PositionToFilthy pos) const 0139 { 0140 Q_UNUSED(pos); 0141 0142 /** 0143 * FIXME: This check of the emptiness should be done 0144 * on the higher/lower level 0145 */ 0146 0147 if(rect.isEmpty()) return rect; 0148 0149 KisFilterConfigurationSP filterConfig = filter(); 0150 if (!filterConfig) return rect; 0151 0152 KisNodeSP parent = this->parent(); 0153 const int lod = parent && parent->projection() ? 0154 parent->projection()->defaultBounds()->currentLevelOfDetail() : 0; 0155 0156 KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); 0157 0158 /** 0159 * If we need some additional pixels even outside of a selection 0160 * for accurate layer filtering, we'll get them! 0161 * And no KisMask::needRect will prevent us from doing this! ;) 0162 * That's why simply we do not call KisMask::needRect here :) 0163 */ 0164 return filter->neededRect(rect, filterConfig.data(), lod); 0165 } 0166