File indexing completed on 2024-05-12 15:58:24
0001 /* 0002 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org> 0003 * SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk> 0004 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "kis_layer.h" 0010 0011 0012 #include <klocalizedstring.h> 0013 #include <QImage> 0014 #include <QBitArray> 0015 #include <QStack> 0016 #include <QMutex> 0017 #include <QMutexLocker> 0018 #include <QReadWriteLock> 0019 #include <QReadLocker> 0020 #include <QWriteLocker> 0021 0022 #include <KoIcon.h> 0023 #include <kis_icon.h> 0024 #include <KoProperties.h> 0025 #include <KoCompositeOpRegistry.h> 0026 #include <KoColorSpace.h> 0027 0028 #include "kis_debug.h" 0029 #include "kis_image.h" 0030 0031 #include "kis_painter.h" 0032 #include "kis_mask.h" 0033 #include "kis_effect_mask.h" 0034 #include "kis_selection_mask.h" 0035 #include "kis_meta_data_store.h" 0036 #include "kis_selection.h" 0037 #include "kis_paint_layer.h" 0038 #include "kis_raster_keyframe_channel.h" 0039 0040 #include "kis_clone_layer.h" 0041 0042 #include "kis_psd_layer_style.h" 0043 #include "kis_layer_projection_plane.h" 0044 #include "layerstyles/kis_layer_style_projection_plane.h" 0045 0046 #include "krita_utils.h" 0047 #include "kis_layer_properties_icons.h" 0048 #include "kis_layer_utils.h" 0049 #include "kis_projection_leaf.h" 0050 #include "KisSafeNodeProjectionStore.h" 0051 0052 0053 class KisCloneLayersList { 0054 public: 0055 void addClone(KisCloneLayerWSP cloneLayer) { 0056 m_clonesList.append(cloneLayer); 0057 } 0058 0059 void removeClone(KisCloneLayerWSP cloneLayer) { 0060 m_clonesList.removeOne(cloneLayer); 0061 } 0062 0063 void setDirty(const QRect &rect) { 0064 Q_FOREACH (KisCloneLayerSP clone, m_clonesList) { 0065 if (clone) { 0066 clone->setDirtyOriginal(rect); 0067 } 0068 } 0069 } 0070 0071 const QList<KisCloneLayerWSP> registeredClones() const { 0072 return m_clonesList; 0073 } 0074 0075 bool hasClones() const { 0076 return !m_clonesList.isEmpty(); 0077 } 0078 0079 private: 0080 QList<KisCloneLayerWSP> m_clonesList; 0081 }; 0082 0083 class KisLayerMasksCache { 0084 public: 0085 KisLayerMasksCache(KisLayer *parent) 0086 : m_parent(parent) 0087 { 0088 } 0089 0090 KisSelectionMaskSP selectionMask() { 0091 QReadLocker readLock(&m_lock); 0092 0093 if (!m_isSelectionMaskValid) { 0094 readLock.unlock(); 0095 0096 QWriteLocker writeLock(&m_lock); 0097 if (!m_isSelectionMaskValid) { 0098 KoProperties properties; 0099 properties.setProperty("active", true); 0100 properties.setProperty("visible", true); 0101 QList<KisNodeSP> masks = m_parent->childNodes(QStringList("KisSelectionMask"), properties); 0102 0103 // return the first visible mask 0104 Q_FOREACH (KisNodeSP mask, masks) { 0105 if (mask) { 0106 m_selectionMask = dynamic_cast<KisSelectionMask*>(mask.data()); 0107 break; 0108 } 0109 } 0110 m_isSelectionMaskValid = true; 0111 } 0112 0113 // return under write lock 0114 return m_selectionMask; 0115 } 0116 0117 // return under read lock 0118 return m_selectionMask; 0119 } 0120 0121 QList<KisEffectMaskSP> effectMasks() { 0122 QReadLocker readLock(&m_lock); 0123 0124 if (!m_isEffectMasksValid) { 0125 readLock.unlock(); 0126 0127 QWriteLocker writeLock(&m_lock); 0128 if (!m_isEffectMasksValid) { 0129 m_effectMasks = m_parent->searchEffectMasks(0); 0130 m_isEffectMasksValid = true; 0131 } 0132 0133 // return under write lock 0134 return m_effectMasks; 0135 } 0136 0137 // return under read lock 0138 return m_effectMasks; 0139 } 0140 0141 void setDirty() 0142 { 0143 QWriteLocker l(&m_lock); 0144 m_isSelectionMaskValid = false; 0145 m_isEffectMasksValid = false; 0146 m_selectionMask = 0; 0147 m_effectMasks.clear(); 0148 } 0149 0150 private: 0151 KisLayer *m_parent; 0152 0153 QReadWriteLock m_lock; 0154 0155 bool m_isSelectionMaskValid = false; 0156 bool m_isEffectMasksValid = false; 0157 KisSelectionMaskSP m_selectionMask; 0158 QList<KisEffectMaskSP> m_effectMasks; 0159 }; 0160 0161 struct Q_DECL_HIDDEN KisLayer::Private 0162 { 0163 Private(KisLayer *q) 0164 : masksCache(q) 0165 { 0166 } 0167 0168 QBitArray channelFlags; 0169 KisMetaData::Store* metaDataStore {nullptr}; 0170 KisCloneLayersList clonesList; 0171 0172 KisPSDLayerStyleSP layerStyle; 0173 KisLayerStyleProjectionPlaneSP layerStyleProjectionPlane; 0174 0175 KisLayerProjectionPlaneSP projectionPlane; 0176 KisSafeNodeProjectionStoreSP safeProjection; 0177 0178 KisLayerMasksCache masksCache; 0179 }; 0180 0181 0182 KisLayer::KisLayer(KisImageWSP image, const QString &name, quint8 opacity) 0183 : KisNode(image) 0184 , m_d(new Private(this)) 0185 { 0186 setName(name); 0187 setOpacity(opacity); 0188 m_d->metaDataStore = new KisMetaData::Store(); 0189 m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this)); 0190 m_d->safeProjection = new KisSafeNodeProjectionStore(); 0191 m_d->safeProjection->setImage(image); 0192 } 0193 0194 KisLayer::KisLayer(const KisLayer& rhs) 0195 : KisNode(rhs) 0196 , m_d(new Private(this)) 0197 { 0198 if (this != &rhs) { 0199 m_d->metaDataStore = new KisMetaData::Store(*rhs.m_d->metaDataStore); 0200 m_d->channelFlags = rhs.m_d->channelFlags; 0201 0202 setName(rhs.name()); 0203 m_d->projectionPlane = toQShared(new KisLayerProjectionPlane(this)); 0204 m_d->safeProjection = new KisSafeNodeProjectionStore(*rhs.m_d->safeProjection); 0205 m_d->safeProjection->setImage(image()); 0206 0207 if (rhs.m_d->layerStyle) { 0208 m_d->layerStyle = rhs.m_d->layerStyle->clone().dynamicCast<KisPSDLayerStyle>(); 0209 0210 if (rhs.m_d->layerStyleProjectionPlane) { 0211 m_d->layerStyleProjectionPlane = toQShared( 0212 new KisLayerStyleProjectionPlane(*rhs.m_d->layerStyleProjectionPlane, 0213 this, 0214 m_d->layerStyle)); 0215 } 0216 } 0217 } 0218 } 0219 0220 KisLayer::~KisLayer() 0221 { 0222 delete m_d->metaDataStore; 0223 delete m_d; 0224 } 0225 0226 const KoColorSpace * KisLayer::colorSpace() const 0227 { 0228 KisPaintDeviceSP dev = original(); 0229 KIS_ASSERT_RECOVER_RETURN_VALUE(dev, KoColorSpaceRegistry::instance()->rgb8()); 0230 return dev->colorSpace(); 0231 } 0232 0233 const KoCompositeOp * KisLayer::compositeOp() const 0234 { 0235 /** 0236 * FIXME: This function duplicates the same function from 0237 * KisMask. We can't move it to KisBaseNode as it doesn't 0238 * know anything about parent() method of KisNode 0239 * Please think it over... 0240 */ 0241 0242 KisNodeSP parentNode = parent(); 0243 if (!parentNode) return 0; 0244 0245 if (!parentNode->colorSpace()) return 0; 0246 const KoCompositeOp* op = parentNode->colorSpace()->compositeOp(compositeOpId()); 0247 return op ? op : parentNode->colorSpace()->compositeOp(COMPOSITE_OVER); 0248 } 0249 0250 KisPSDLayerStyleSP KisLayer::layerStyle() const 0251 { 0252 return m_d->layerStyle; 0253 } 0254 0255 void KisLayer::setLayerStyle(KisPSDLayerStyleSP layerStyle) 0256 { 0257 if (layerStyle) { 0258 KIS_SAFE_ASSERT_RECOVER_NOOP(layerStyle->hasLocalResourcesSnapshot()); 0259 0260 m_d->layerStyle = layerStyle; 0261 0262 KisLayerStyleProjectionPlaneSP plane = !layerStyle->isEmpty() ? 0263 KisLayerStyleProjectionPlaneSP(new KisLayerStyleProjectionPlane(this)) : 0264 KisLayerStyleProjectionPlaneSP(0); 0265 0266 m_d->layerStyleProjectionPlane = plane; 0267 } else { 0268 m_d->layerStyleProjectionPlane.clear(); 0269 m_d->layerStyle.clear(); 0270 } 0271 } 0272 0273 KisBaseNode::PropertyList KisLayer::sectionModelProperties() const 0274 { 0275 KisBaseNode::PropertyList l = KisBaseNode::sectionModelProperties(); 0276 l << KisBaseNode::Property(KoID("opacity", i18n("Opacity")), i18n("%1%", percentOpacity())); 0277 0278 const KoCompositeOp * compositeOp = this->compositeOp(); 0279 0280 if (compositeOp) { 0281 l << KisBaseNode::Property(KoID("compositeop", i18n("Blending Mode")), compositeOp->description()); 0282 } 0283 0284 if (m_d->layerStyle && !m_d->layerStyle->isEmpty()) { 0285 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::layerStyle, m_d->layerStyle->isEnabled()); 0286 } 0287 0288 l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::inheritAlpha, alphaChannelDisabled()); 0289 0290 return l; 0291 } 0292 0293 void KisLayer::setSectionModelProperties(const KisBaseNode::PropertyList &properties) 0294 { 0295 KisBaseNode::setSectionModelProperties(properties); 0296 0297 Q_FOREACH (const KisBaseNode::Property &property, properties) { 0298 if (property.id == KisLayerPropertiesIcons::inheritAlpha.id()) { 0299 disableAlphaChannel(property.state.toBool()); 0300 } 0301 0302 if (property.id == KisLayerPropertiesIcons::layerStyle.id()) { 0303 if (m_d->layerStyle && 0304 m_d->layerStyle->isEnabled() != property.state.toBool()) { 0305 0306 m_d->layerStyle->setEnabled(property.state.toBool()); 0307 0308 baseNodeChangedCallback(); 0309 baseNodeInvalidateAllFramesCallback(); 0310 } 0311 } 0312 } 0313 } 0314 0315 void KisLayer::disableAlphaChannel(bool disable) 0316 { 0317 QBitArray newChannelFlags = m_d->channelFlags; 0318 0319 if(newChannelFlags.isEmpty()) 0320 newChannelFlags = colorSpace()->channelFlags(true, true); 0321 0322 if(disable) 0323 newChannelFlags &= colorSpace()->channelFlags(true, false); 0324 else 0325 newChannelFlags |= colorSpace()->channelFlags(false, true); 0326 0327 setChannelFlags(newChannelFlags); 0328 } 0329 0330 bool KisLayer::alphaChannelDisabled() const 0331 { 0332 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(colorSpace(), false); 0333 QBitArray flags = colorSpace()->channelFlags(false, true) & m_d->channelFlags; 0334 return flags.count(true) == 0 && !m_d->channelFlags.isEmpty(); 0335 } 0336 0337 0338 void KisLayer::setChannelFlags(const QBitArray & channelFlags) 0339 { 0340 Q_ASSERT(channelFlags.isEmpty() ||((quint32)channelFlags.count() == colorSpace()->channelCount())); 0341 0342 if (KritaUtils::compareChannelFlags(channelFlags, 0343 this->channelFlags())) { 0344 return; 0345 } 0346 0347 if (!channelFlags.isEmpty() && 0348 channelFlags == QBitArray(channelFlags.size(), true)) { 0349 0350 m_d->channelFlags.clear(); 0351 } else { 0352 m_d->channelFlags = channelFlags; 0353 } 0354 0355 baseNodeChangedCallback(); 0356 baseNodeInvalidateAllFramesCallback(); 0357 } 0358 0359 QBitArray & KisLayer::channelFlags() const 0360 { 0361 return m_d->channelFlags; 0362 } 0363 0364 bool KisLayer::temporary() const 0365 { 0366 return nodeProperties().boolProperty("temporary", false); 0367 } 0368 0369 void KisLayer::setTemporary(bool t) 0370 { 0371 setNodeProperty("temporary", t); 0372 } 0373 0374 void KisLayer::setImage(KisImageWSP image) 0375 { 0376 // we own the projection device, so we should take care about it 0377 KisPaintDeviceSP projection = this->projection(); 0378 if (projection && projection != original()) { 0379 projection->setDefaultBounds(new KisDefaultBounds(image)); 0380 } 0381 m_d->safeProjection->setImage(image); 0382 0383 KisNode::setImage(image); 0384 } 0385 0386 bool KisLayer::canMergeAndKeepBlendOptions(KisLayerSP otherLayer) 0387 { 0388 return 0389 this->compositeOpId() == otherLayer->compositeOpId() && 0390 this->opacity() == otherLayer->opacity() && 0391 this->channelFlags() == otherLayer->channelFlags() && 0392 !this->layerStyle() && !otherLayer->layerStyle() && 0393 (this->colorSpace() == otherLayer->colorSpace() || 0394 *this->colorSpace() == *otherLayer->colorSpace()); 0395 } 0396 0397 KisLayerSP KisLayer::createMergedLayerTemplate(KisLayerSP prevLayer) 0398 { 0399 const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer); 0400 0401 KisLayerSP newLayer = new KisPaintLayer(image(), prevLayer->name(), OPACITY_OPAQUE_U8); 0402 0403 if (keepBlendingOptions) { 0404 newLayer->setCompositeOpId(compositeOpId()); 0405 newLayer->setOpacity(opacity()); 0406 newLayer->setChannelFlags(channelFlags()); 0407 } 0408 0409 return newLayer; 0410 } 0411 0412 void KisLayer::fillMergedLayerTemplate(KisLayerSP dstLayer, KisLayerSP prevLayer) 0413 { 0414 const bool keepBlendingOptions = canMergeAndKeepBlendOptions(prevLayer); 0415 0416 QRect layerProjectionExtent = this->projection()->extent(); 0417 QRect prevLayerProjectionExtent = prevLayer->projection()->extent(); 0418 bool alphaDisabled = this->alphaChannelDisabled(); 0419 bool prevAlphaDisabled = prevLayer->alphaChannelDisabled(); 0420 0421 KisPaintDeviceSP mergedDevice = dstLayer->paintDevice(); 0422 0423 if (!keepBlendingOptions) { 0424 KisPainter gc(mergedDevice); 0425 0426 KisImageSP imageSP = image().toStrongRef(); 0427 if (!imageSP) { 0428 return; 0429 } 0430 0431 //Copy the pixels of previous layer with their actual alpha value 0432 prevLayer->disableAlphaChannel(false); 0433 0434 prevLayer->projectionPlane()->apply(&gc, prevLayerProjectionExtent | imageSP->bounds()); 0435 0436 //Restore the previous prevLayer disableAlpha status for correct undo/redo 0437 prevLayer->disableAlphaChannel(prevAlphaDisabled); 0438 0439 //Paint the pixels of the current layer, using their actual alpha value 0440 if (alphaDisabled == prevAlphaDisabled) { 0441 this->disableAlphaChannel(false); 0442 } 0443 0444 this->projectionPlane()->apply(&gc, layerProjectionExtent | imageSP->bounds()); 0445 0446 //Restore the layer disableAlpha status for correct undo/redo 0447 this->disableAlphaChannel(alphaDisabled); 0448 } 0449 else { 0450 //Copy prevLayer 0451 KisPaintDeviceSP srcDev = prevLayer->projection(); 0452 mergedDevice->makeCloneFrom(srcDev, srcDev->extent()); 0453 0454 //Paint layer on the copy 0455 KisPainter gc(mergedDevice); 0456 gc.bitBlt(layerProjectionExtent.topLeft(), this->projection(), layerProjectionExtent); 0457 } 0458 } 0459 0460 void KisLayer::registerClone(KisCloneLayerWSP clone) 0461 { 0462 m_d->clonesList.addClone(clone); 0463 } 0464 0465 void KisLayer::unregisterClone(KisCloneLayerWSP clone) 0466 { 0467 m_d->clonesList.removeClone(clone); 0468 } 0469 0470 const QList<KisCloneLayerWSP> KisLayer::registeredClones() const 0471 { 0472 return m_d->clonesList.registeredClones(); 0473 } 0474 0475 bool KisLayer::hasClones() const 0476 { 0477 return m_d->clonesList.hasClones(); 0478 } 0479 0480 void KisLayer::updateClones(const QRect &rect) 0481 { 0482 m_d->clonesList.setDirty(rect); 0483 } 0484 0485 void KisLayer::notifyChildMaskChanged() 0486 { 0487 m_d->masksCache.setDirty(); 0488 } 0489 0490 KisSelectionMaskSP KisLayer::selectionMask() const 0491 { 0492 return m_d->masksCache.selectionMask(); 0493 } 0494 0495 KisSelectionSP KisLayer::selection() const 0496 { 0497 KisSelectionMaskSP mask = selectionMask(); 0498 0499 if (mask) { 0500 return mask->selection(); 0501 } 0502 0503 KisImageSP image = this->image(); 0504 if (image) { 0505 return image->globalSelection(); 0506 } 0507 return KisSelectionSP(); 0508 } 0509 0510 /////////////////////////////////////////////////////////////////////// 0511 /////////////////////////////////////////////////////////////////////// 0512 0513 QList<KisEffectMaskSP> KisLayer::effectMasks() const 0514 { 0515 return m_d->masksCache.effectMasks(); 0516 } 0517 0518 QList<KisEffectMaskSP> KisLayer::effectMasks(KisNodeSP lastNode) const 0519 { 0520 if (lastNode.isNull()) { 0521 return effectMasks(); 0522 } else { 0523 // happens rarely. 0524 return searchEffectMasks(lastNode); 0525 } 0526 } 0527 0528 QList<KisEffectMaskSP> KisLayer::searchEffectMasks(KisNodeSP lastNode) const 0529 { 0530 QList<KisEffectMaskSP> masks; 0531 0532 KIS_SAFE_ASSERT_RECOVER_NOOP(projectionLeaf()); 0533 0534 KisProjectionLeafSP child = projectionLeaf()->firstChild(); 0535 while (child) { 0536 if (child->node() == lastNode) break; 0537 0538 KIS_SAFE_ASSERT_RECOVER_NOOP(child); 0539 KIS_SAFE_ASSERT_RECOVER_NOOP(child->node()); 0540 0541 if (child->visible()) { 0542 KisEffectMaskSP mask = dynamic_cast<KisEffectMask*>(const_cast<KisNode*>(child->node().data())); 0543 if (mask) { 0544 masks.append(mask); 0545 } 0546 } 0547 0548 child = child->nextSibling(); 0549 } 0550 0551 return masks; 0552 } 0553 0554 bool KisLayer::hasEffectMasks() const 0555 { 0556 return !m_d->masksCache.effectMasks().isEmpty(); 0557 } 0558 0559 QRect KisLayer::masksChangeRect(const QList<KisEffectMaskSP> &masks, 0560 const QRect &requestedRect, 0561 bool &rectVariesFlag) const 0562 { 0563 rectVariesFlag = false; 0564 0565 QRect prevChangeRect = requestedRect; 0566 0567 /** 0568 * We set default value of the change rect for the case 0569 * when there is no mask at all 0570 */ 0571 QRect changeRect = requestedRect; 0572 0573 Q_FOREACH (const KisEffectMaskSP& mask, masks) { 0574 changeRect = mask->changeRect(prevChangeRect); 0575 0576 if (changeRect != prevChangeRect) 0577 rectVariesFlag = true; 0578 0579 prevChangeRect = changeRect; 0580 } 0581 0582 return changeRect; 0583 } 0584 0585 QRect KisLayer::masksNeedRect(const QList<KisEffectMaskSP> &masks, 0586 const QRect &changeRect, 0587 QStack<QRect> &applyRects, 0588 bool &rectVariesFlag) const 0589 { 0590 rectVariesFlag = false; 0591 0592 QRect prevNeedRect = changeRect; 0593 QRect needRect; 0594 0595 for (qint32 i = masks.size() - 1; i >= 0; i--) { 0596 applyRects.push(prevNeedRect); 0597 0598 needRect = masks[i]->needRect(prevNeedRect); 0599 0600 if (prevNeedRect != needRect) 0601 rectVariesFlag = true; 0602 0603 prevNeedRect = needRect; 0604 } 0605 0606 return needRect; 0607 } 0608 0609 KisNode::PositionToFilthy calculatePositionToFilthy(KisNodeSP nodeInQuestion, 0610 KisNodeSP filthy, 0611 KisNodeSP parent) 0612 { 0613 if (parent == filthy || parent != filthy->parent()) { 0614 return KisNode::N_ABOVE_FILTHY; 0615 } 0616 0617 if (nodeInQuestion == filthy) { 0618 return KisNode::N_FILTHY; 0619 } 0620 0621 KisNodeSP node = nodeInQuestion->prevSibling(); 0622 while (node) { 0623 if (node == filthy) { 0624 return KisNode::N_ABOVE_FILTHY; 0625 } 0626 node = node->prevSibling(); 0627 } 0628 0629 return KisNode::N_BELOW_FILTHY; 0630 } 0631 0632 QRect KisLayer::applyMasks(const KisPaintDeviceSP source, 0633 KisPaintDeviceSP destination, 0634 const QRect &requestedRect, 0635 KisNodeSP filthyNode, 0636 KisNodeSP lastNode) const 0637 { 0638 Q_ASSERT(source); 0639 Q_ASSERT(destination); 0640 0641 QList<KisEffectMaskSP> masks = effectMasks(lastNode); 0642 QRect changeRect; 0643 QRect needRect; 0644 0645 if (masks.isEmpty()) { 0646 changeRect = requestedRect; 0647 if (source != destination) { 0648 copyOriginalToProjection(source, destination, requestedRect); 0649 } 0650 } else { 0651 QStack<QRect> applyRects; 0652 bool changeRectVaries; 0653 bool needRectVaries; 0654 0655 /** 0656 * FIXME: Assume that varying of the changeRect has already 0657 * been taken into account while preparing walkers 0658 */ 0659 changeRectVaries = false; 0660 changeRect = requestedRect; 0661 //changeRect = masksChangeRect(masks, requestedRect, 0662 // changeRectVaries); 0663 0664 needRect = masksNeedRect(masks, changeRect, 0665 applyRects, needRectVaries); 0666 0667 if (!changeRectVaries && !needRectVaries) { 0668 /** 0669 * A bit of optimization: 0670 * All filters will read/write exactly from/to the requested 0671 * rect so we needn't create temporary paint device, 0672 * just apply it onto destination 0673 */ 0674 Q_ASSERT(needRect == requestedRect); 0675 0676 if (source != destination) { 0677 copyOriginalToProjection(source, destination, needRect); 0678 } 0679 0680 Q_FOREACH (const KisEffectMaskSP& mask, masks) { 0681 const QRect maskApplyRect = applyRects.pop(); 0682 const QRect maskNeedRect = 0683 applyRects.isEmpty() ? needRect : applyRects.top(); 0684 0685 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this)); 0686 mask->apply(destination, maskApplyRect, maskNeedRect, maskPosition); 0687 } 0688 Q_ASSERT(applyRects.isEmpty()); 0689 } else { 0690 /** 0691 * We can't eliminate additional copy-op 0692 * as filters' behaviour may be quite insane here, 0693 * so let them work on their own paintDevice =) 0694 */ 0695 0696 KisPaintDeviceSP tempDevice = new KisPaintDevice(colorSpace()); 0697 tempDevice->prepareClone(source); 0698 copyOriginalToProjection(source, tempDevice, needRect); 0699 0700 QRect maskApplyRect = applyRects.pop(); 0701 QRect maskNeedRect = needRect; 0702 0703 Q_FOREACH (const KisEffectMaskSP& mask, masks) { 0704 PositionToFilthy maskPosition = calculatePositionToFilthy(mask, filthyNode, const_cast<KisLayer*>(this)); 0705 mask->apply(tempDevice, maskApplyRect, maskNeedRect, maskPosition); 0706 0707 if (!applyRects.isEmpty()) { 0708 maskNeedRect = maskApplyRect; 0709 maskApplyRect = applyRects.pop(); 0710 } 0711 } 0712 Q_ASSERT(applyRects.isEmpty()); 0713 0714 KisPainter::copyAreaOptimized(changeRect.topLeft(), tempDevice, destination, changeRect); 0715 } 0716 } 0717 0718 return changeRect; 0719 } 0720 0721 QRect KisLayer::updateProjection(const QRect& rect, KisNodeSP filthyNode) 0722 { 0723 QRect updatedRect = rect; 0724 KisPaintDeviceSP originalDevice = original(); 0725 if (!rect.isValid() || 0726 (!visible() && !isIsolatedRoot() && !hasClones()) || 0727 !originalDevice) return QRect(); 0728 0729 if (!needProjection() && !hasEffectMasks()) { 0730 m_d->safeProjection->releaseDevice(); 0731 } else { 0732 0733 if (!updatedRect.isEmpty()) { 0734 KisPaintDeviceSP projection = m_d->safeProjection->getDeviceLazy(originalDevice); 0735 updatedRect = applyMasks(originalDevice, projection, 0736 updatedRect, filthyNode, 0); 0737 } 0738 } 0739 0740 return updatedRect; 0741 } 0742 0743 QRect KisLayer::partialChangeRect(KisNodeSP lastNode, const QRect& rect) 0744 { 0745 bool changeRectVaries = false; 0746 QRect changeRect = outgoingChangeRect(rect); 0747 changeRect = masksChangeRect(effectMasks(lastNode), changeRect, 0748 changeRectVaries); 0749 0750 return changeRect; 0751 } 0752 0753 /** 0754 * \p rect is a dirty rect in layer's original() coordinates! 0755 */ 0756 void KisLayer::buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect& rect) 0757 { 0758 QRect changeRect = partialChangeRect(lastNode, rect); 0759 0760 KisPaintDeviceSP originalDevice = original(); 0761 0762 KIS_SAFE_ASSERT_RECOVER_RETURN(needProjection() || hasEffectMasks()); 0763 0764 if (!changeRect.isEmpty()) { 0765 applyMasks(originalDevice, projection, 0766 changeRect, this, lastNode); 0767 } 0768 } 0769 0770 bool KisLayer::needProjection() const 0771 { 0772 return false; 0773 } 0774 0775 void KisLayer::copyOriginalToProjection(const KisPaintDeviceSP original, 0776 KisPaintDeviceSP projection, 0777 const QRect& rect) const 0778 { 0779 KisPainter::copyAreaOptimized(rect.topLeft(), original, projection, rect); 0780 } 0781 0782 KisAbstractProjectionPlaneSP KisLayer::projectionPlane() const 0783 { 0784 return m_d->layerStyleProjectionPlane ? 0785 KisAbstractProjectionPlaneSP(m_d->layerStyleProjectionPlane) : 0786 KisAbstractProjectionPlaneSP(m_d->projectionPlane); 0787 } 0788 0789 KisLayerProjectionPlaneSP KisLayer::internalProjectionPlane() const 0790 { 0791 return m_d->projectionPlane; 0792 } 0793 0794 KisPaintDeviceSP KisLayer::projection() const 0795 { 0796 KisPaintDeviceSP originalDevice = original(); 0797 0798 return needProjection() || hasEffectMasks() ? 0799 m_d->safeProjection->getDeviceLazy(originalDevice) : originalDevice; 0800 } 0801 0802 QRect KisLayer::tightUserVisibleBounds() const 0803 { 0804 QRect changeRect = exactBounds(); 0805 0806 /// we do not use incomingChangeRect() here, because 0807 /// exactBounds() already takes it into account (it 0808 /// was used while preparing original()) 0809 0810 bool changeRectVaries; 0811 changeRect = outgoingChangeRect(changeRect); 0812 changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries); 0813 0814 return changeRect; 0815 } 0816 0817 QRect KisLayer::amortizedProjectionRectForCleanupInChangePass() const 0818 { 0819 return projection()->exactBoundsAmortized(); 0820 } 0821 0822 QRect KisLayer::changeRect(const QRect &rect, PositionToFilthy pos) const 0823 { 0824 QRect changeRect = rect; 0825 changeRect = incomingChangeRect(changeRect); 0826 0827 if(pos == KisNode::N_FILTHY) { 0828 QRect projectionToBeUpdated = amortizedProjectionRectForCleanupInChangePass() & changeRect; 0829 0830 bool changeRectVaries; 0831 changeRect = outgoingChangeRect(changeRect); 0832 changeRect = masksChangeRect(effectMasks(), changeRect, changeRectVaries); 0833 0834 /** 0835 * If the projection contains some dirty areas we should also 0836 * add them to the change rect, because they might have 0837 * changed. E.g. when a visibility of the mask has chnaged 0838 * while the parent layer was invinisble. 0839 */ 0840 0841 if (!projectionToBeUpdated.isEmpty() && 0842 !changeRect.contains(projectionToBeUpdated)) { 0843 0844 changeRect |= projectionToBeUpdated; 0845 } 0846 } 0847 0848 // TODO: string comparison: optimize! 0849 if (pos != KisNode::N_FILTHY && 0850 pos != KisNode::N_FILTHY_PROJECTION && 0851 compositeOpId() != COMPOSITE_COPY) { 0852 0853 changeRect |= rect; 0854 } 0855 0856 return changeRect; 0857 } 0858 0859 void KisLayer::childNodeChanged(KisNodeSP changedChildNode) 0860 { 0861 if (dynamic_cast<KisMask*>(changedChildNode.data())) { 0862 notifyChildMaskChanged(); 0863 } 0864 } 0865 0866 QRect KisLayer::incomingChangeRect(const QRect &rect) const 0867 { 0868 return rect; 0869 } 0870 0871 QRect KisLayer::outgoingChangeRect(const QRect &rect) const 0872 { 0873 return rect; 0874 } 0875 0876 QRect KisLayer::needRectForOriginal(const QRect &rect) const 0877 { 0878 QRect needRect = rect; 0879 0880 const QList<KisEffectMaskSP> masks = effectMasks(); 0881 0882 if (!masks.isEmpty()) { 0883 QStack<QRect> applyRects; 0884 bool needRectVaries; 0885 0886 needRect = masksNeedRect(masks, rect, 0887 applyRects, needRectVaries); 0888 } 0889 0890 return needRect; 0891 } 0892 0893 QImage KisLayer::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode) 0894 { 0895 if (w == 0 || h == 0) { 0896 return QImage(); 0897 } 0898 0899 KisPaintDeviceSP originalDevice = original(); 0900 0901 return originalDevice ? 0902 originalDevice->createThumbnail(w, h, aspectRatioMode, 1, 0903 KoColorConversionTransformation::internalRenderingIntent(), 0904 KoColorConversionTransformation::internalConversionFlags()) : QImage(); 0905 } 0906 0907 QImage KisLayer::createThumbnailForFrame(qint32 w, qint32 h, int time, Qt::AspectRatioMode aspectRatioMode) 0908 { 0909 if (w == 0 || h == 0) { 0910 return QImage(); 0911 } 0912 0913 KisPaintDeviceSP originalDevice = original(); 0914 if (originalDevice ) { 0915 KisRasterKeyframeChannel *channel = originalDevice->keyframeChannel(); 0916 0917 if (channel) { 0918 KisPaintDeviceSP targetDevice = new KisPaintDevice(colorSpace()); 0919 KisRasterKeyframeSP keyframe = channel->activeKeyframeAt<KisRasterKeyframe>(time); 0920 keyframe->writeFrameToDevice(targetDevice); 0921 return targetDevice->createThumbnail(w, h, aspectRatioMode, 1, 0922 KoColorConversionTransformation::internalRenderingIntent(), 0923 KoColorConversionTransformation::internalConversionFlags()); 0924 } 0925 } 0926 0927 return createThumbnail(w, h); 0928 } 0929 0930 qint32 KisLayer::x() const 0931 { 0932 KisPaintDeviceSP originalDevice = original(); 0933 return originalDevice ? originalDevice->x() : 0; 0934 } 0935 qint32 KisLayer::y() const 0936 { 0937 KisPaintDeviceSP originalDevice = original(); 0938 return originalDevice ? originalDevice->y() : 0; 0939 } 0940 void KisLayer::setX(qint32 x) 0941 { 0942 KisPaintDeviceSP originalDevice = original(); 0943 if (originalDevice) 0944 originalDevice->setX(x); 0945 } 0946 void KisLayer::setY(qint32 y) 0947 { 0948 KisPaintDeviceSP originalDevice = original(); 0949 if (originalDevice) 0950 originalDevice->setY(y); 0951 } 0952 0953 QRect KisLayer::layerExtentImpl(bool needExactBounds) const 0954 { 0955 QRect additionalMaskExtent = QRect(); 0956 QList<KisEffectMaskSP> effectMasks = this->effectMasks(); 0957 0958 Q_FOREACH(KisEffectMaskSP mask, effectMasks) { 0959 additionalMaskExtent |= mask->nonDependentExtent(); 0960 } 0961 0962 KisPaintDeviceSP originalDevice = original(); 0963 QRect layerExtent; 0964 0965 if (originalDevice) { 0966 layerExtent = needExactBounds ? 0967 originalDevice->exactBounds() : 0968 originalDevice->extent(); 0969 } 0970 0971 QRect additionalCompositeOpExtent; 0972 if (compositeOpId() == COMPOSITE_COPY || 0973 compositeOpId() == COMPOSITE_DESTINATION_IN || 0974 compositeOpId() == COMPOSITE_DESTINATION_ATOP) { 0975 0976 additionalCompositeOpExtent = originalDevice->defaultBounds()->bounds(); 0977 } 0978 0979 return layerExtent | additionalMaskExtent | additionalCompositeOpExtent; 0980 } 0981 0982 QRect KisLayer::extent() const 0983 { 0984 return layerExtentImpl(false); 0985 } 0986 0987 QRect KisLayer::exactBounds() const 0988 { 0989 return layerExtentImpl(true); 0990 } 0991 0992 KisLayerSP KisLayer::parentLayer() const 0993 { 0994 return qobject_cast<KisLayer*>(parent().data()); 0995 } 0996 0997 KisMetaData::Store* KisLayer::metaData() 0998 { 0999 return m_d->metaDataStore; 1000 } 1001