diff --git a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp index ea88544ee2..1583567a0a 100644 --- a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp +++ b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.cpp @@ -1,46 +1,72 @@ /* * Copyright (c) 2019 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisLayerStyleKnockoutBlower.h" #include "kis_painter.h" #include "KoCompositeOpRegistry.h" -KisSelectionSP KisLayerStyleKnockoutBlower::knockoutSelection() const +KisSelectionSP KisLayerStyleKnockoutBlower::knockoutSelectionLazy() { - return m_knockoutSelection; + { + QReadLocker l(&m_lock); + if (m_knockoutSelection) { + return m_knockoutSelection; + } + } + + { + QWriteLocker l(&m_lock); + if (m_knockoutSelection) { + return m_knockoutSelection; + } else { + m_knockoutSelection = new KisSelection(new KisSelectionEmptyBounds(0)); + return m_knockoutSelection; + } + } } void KisLayerStyleKnockoutBlower::setKnockoutSelection(KisSelectionSP selection) { + QWriteLocker l(&m_lock); m_knockoutSelection = selection; } +void KisLayerStyleKnockoutBlower::resetKnockoutSelection() +{ + QWriteLocker l(&m_lock); + m_knockoutSelection = 0; +} + void KisLayerStyleKnockoutBlower::apply(KisPainter *painter, KisPaintDeviceSP mergedStyle, const QRect &rect) const { + QReadLocker l(&m_lock); + KIS_SAFE_ASSERT_RECOVER_NOOP(m_knockoutSelection); painter->setOpacity(OPACITY_OPAQUE_U8); painter->setChannelFlags(QBitArray()); painter->setCompositeOp(COMPOSITE_COPY); painter->setSelection(m_knockoutSelection); painter->bitBlt(rect.topLeft(), mergedStyle, rect); } -bool KisLayerStyleKnockoutBlower::isEmpty() const { +bool KisLayerStyleKnockoutBlower::isEmpty() const +{ + QReadLocker l(&m_lock); return !m_knockoutSelection; } diff --git a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h index b12cca6644..3d6a1c8d6f 100644 --- a/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h +++ b/libs/image/layerstyles/KisLayerStyleKnockoutBlower.h @@ -1,40 +1,44 @@ /* * Copyright (c) 2019 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KISLAYERSTYLEKNOCKOUTBLOWER_H #define KISLAYERSTYLEKNOCKOUTBLOWER_H #include "kis_selection.h" +#include class KisPainter; class KisLayerStyleKnockoutBlower { public: - KisSelectionSP knockoutSelection() const; + KisSelectionSP knockoutSelectionLazy(); + void setKnockoutSelection(KisSelectionSP selection); + void resetKnockoutSelection(); void apply(KisPainter *painter, KisPaintDeviceSP mergedStyle, const QRect &rect) const; bool isEmpty() const; private: + mutable QReadWriteLock m_lock; KisSelectionSP m_knockoutSelection; }; #endif // KISLAYERSTYLEKNOCKOUTBLOWER_H diff --git a/libs/image/layerstyles/kis_layer_style_projection_plane.cpp b/libs/image/layerstyles/kis_layer_style_projection_plane.cpp index 19bf57fea0..c00214cee0 100644 --- a/libs/image/layerstyles/kis_layer_style_projection_plane.cpp +++ b/libs/image/layerstyles/kis_layer_style_projection_plane.cpp @@ -1,408 +1,410 @@ /* * Copyright (c) 2015 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_style_projection_plane.h" #include "kis_global.h" #include "kis_layer_style_filter_projection_plane.h" #include "kis_layer_projection_plane.h" #include "kis_psd_layer_style.h" #include "kis_ls_drop_shadow_filter.h" #include "kis_ls_satin_filter.h" #include "kis_ls_overlay_filter.h" #include "kis_ls_stroke_filter.h" #include "kis_ls_bevel_emboss_filter.h" #include "kis_projection_leaf.h" #include "kis_cached_paint_device.h" #include "kis_painter.h" #include "kis_ls_utils.h" #include "KisLayerStyleKnockoutBlower.h" struct Q_DECL_HIDDEN KisLayerStyleProjectionPlane::Private { KisLayerProjectionPlaneWSP sourceProjectionPlane; QVector stylesBefore; QVector stylesAfter; QVector stylesOverlay; KisCachedPaintDevice cachedPaintDevice; KisCachedSelection cachedSelection; KisLayer *sourceLayer = 0; KisPSDLayerStyleSP style; bool canHaveChildNodes = false; bool dependsOnLowerNodes = false; void initSourcePlane(KisLayer *sourceLayer) { KIS_SAFE_ASSERT_RECOVER_RETURN(sourceLayer); sourceProjectionPlane = sourceLayer->internalProjectionPlane(); canHaveChildNodes = sourceLayer->projectionLeaf()->canHaveChildLayers(); dependsOnLowerNodes = sourceLayer->projectionLeaf()->dependsOnLowerNodes(); this->sourceLayer = sourceLayer; } QVector allStyles() const { return stylesBefore + stylesOverlay + stylesAfter; } bool hasOverlayStyles() const { Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesOverlay) { if (!plane->isEmpty()) return true; } return false; } bool hasKnockoutStyles() const { Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesBefore) { if (!plane->knockoutBlower()->isEmpty()) return true; } Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, stylesAfter) { if (!plane->knockoutBlower()->isEmpty()) return true; } return false; } void applyComplexPlane(KisPainter *painter, KisLayerStyleFilterProjectionPlaneSP plane, const QRect &rect, KisPaintDeviceSP originalClone); }; KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(KisLayer *sourceLayer) : m_d(new Private) { KisPSDLayerStyleSP style = sourceLayer->layerStyle(); KIS_ASSERT_RECOVER(style) { style = toQShared(new KisPSDLayerStyle()); } init(sourceLayer, style); } KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(const KisLayerStyleProjectionPlane &rhs, KisLayer *sourceLayer, KisPSDLayerStyleSP clonedStyle) : m_d(new Private) { m_d->initSourcePlane(sourceLayer); m_d->style = clonedStyle; KIS_SAFE_ASSERT_RECOVER(m_d->style) { m_d->style = toQShared(new KisPSDLayerStyle()); } Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, rhs.m_d->allStyles()) { m_d->stylesBefore << toQShared(new KisLayerStyleFilterProjectionPlane(*plane, sourceLayer, m_d->style)); } } // for testing purposes only! KisLayerStyleProjectionPlane::KisLayerStyleProjectionPlane(KisLayer *sourceLayer, KisPSDLayerStyleSP layerStyle) : m_d(new Private) { init(sourceLayer, layerStyle); } void KisLayerStyleProjectionPlane::init(KisLayer *sourceLayer, KisPSDLayerStyleSP style) { KIS_SAFE_ASSERT_RECOVER_RETURN(sourceLayer); m_d->initSourcePlane(sourceLayer); m_d->style = style; { KisLayerStyleFilterProjectionPlane *dropShadow = new KisLayerStyleFilterProjectionPlane(sourceLayer); dropShadow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::DropShadow), style); m_d->stylesBefore << toQShared(dropShadow); } { KisLayerStyleFilterProjectionPlane *outerGlow = new KisLayerStyleFilterProjectionPlane(sourceLayer); outerGlow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::OuterGlow), style); m_d->stylesAfter << toQShared(outerGlow); } { KisLayerStyleFilterProjectionPlane *stroke = new KisLayerStyleFilterProjectionPlane(sourceLayer); stroke->setStyle(new KisLsStrokeFilter(), style); m_d->stylesAfter << toQShared(stroke); } { KisLayerStyleFilterProjectionPlane *bevelEmboss = new KisLayerStyleFilterProjectionPlane(sourceLayer); bevelEmboss->setStyle(new KisLsBevelEmbossFilter(), style); m_d->stylesAfter << toQShared(bevelEmboss); } { KisLayerStyleFilterProjectionPlane *patternOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); patternOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Pattern), style); m_d->stylesOverlay << toQShared(patternOverlay); } { KisLayerStyleFilterProjectionPlane *gradientOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); gradientOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Gradient), style); m_d->stylesOverlay << toQShared(gradientOverlay); } { KisLayerStyleFilterProjectionPlane *colorOverlay = new KisLayerStyleFilterProjectionPlane(sourceLayer); colorOverlay->setStyle(new KisLsOverlayFilter(KisLsOverlayFilter::Color), style); m_d->stylesOverlay << toQShared(colorOverlay); } { KisLayerStyleFilterProjectionPlane *satin = new KisLayerStyleFilterProjectionPlane(sourceLayer); satin->setStyle(new KisLsSatinFilter(), style); m_d->stylesOverlay << toQShared(satin); } { KisLayerStyleFilterProjectionPlane *innerGlow = new KisLayerStyleFilterProjectionPlane(sourceLayer); innerGlow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::InnerGlow), style); m_d->stylesOverlay << toQShared(innerGlow); } { KisLayerStyleFilterProjectionPlane *innerShadow = new KisLayerStyleFilterProjectionPlane(sourceLayer); innerShadow->setStyle(new KisLsDropShadowFilter(KisLsDropShadowFilter::InnerShadow), style); m_d->stylesOverlay << toQShared(innerShadow); } } KisLayerStyleProjectionPlane::~KisLayerStyleProjectionPlane() { } KisAbstractProjectionPlaneSP KisLayerStyleProjectionPlane::factoryObject(KisLayer *sourceLayer) { Q_ASSERT(sourceLayer); return toQShared(new KisLayerStyleProjectionPlane(sourceLayer)); } QRect KisLayerStyleProjectionPlane::recalculate(const QRect& rect, KisNodeSP filthyNode) { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect result = sourcePlane->recalculate(stylesNeedRect(rect), filthyNode); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { plane->recalculate(rect, filthyNode); } } return result; } void KisLayerStyleProjectionPlane::Private::applyComplexPlane(KisPainter *painter, KisLayerStyleFilterProjectionPlaneSP plane, const QRect &rect, KisPaintDeviceSP originalClone) { if (plane->isEmpty()) return; if (!plane->knockoutBlower()->isEmpty()) { KisCachedPaintDevice::Guard d1(originalClone, cachedPaintDevice); KisPaintDeviceSP mergedStyle = d1.device(); mergedStyle->makeCloneFromRough(originalClone, rect); KisPainter overlayPainter(mergedStyle); plane->apply(&overlayPainter, rect); plane->knockoutBlower()->apply(painter, mergedStyle, rect); } else { plane->apply(painter, rect); } } void KisLayerStyleProjectionPlane::apply(KisPainter *painter, const QRect &rect) { KisLayerProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); if (m_d->style->isEnabled()) { if (m_d->hasOverlayStyles() || m_d->hasKnockoutStyles()) { KisCachedPaintDevice::Guard d1(painter->device(), m_d->cachedPaintDevice); KisPaintDeviceSP originalClone = d1.device(); originalClone->makeCloneFromRough(painter->device(), rect); Q_FOREACH (const KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesBefore) { m_d->applyComplexPlane(painter, plane, rect, originalClone); } if (m_d->hasOverlayStyles()) { KisCachedSelection::Guard s1(m_d->cachedSelection); KisSelectionSP knockoutSelection = s1.selection(); KisLsUtils::selectionFromAlphaChannel(m_d->sourceLayer->projection(), knockoutSelection, rect); KisCachedPaintDevice::Guard d2(painter->device(), m_d->cachedPaintDevice); KisPaintDeviceSP sourceProjection = d2.device(); sourceProjection->makeCloneFromRough(painter->device(), rect); { KisPainter overlayPainter(sourceProjection); sourcePlane->applyMaxOutAlpha(&overlayPainter, rect); Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesOverlay) { plane->apply(&overlayPainter, rect); } } KisLayerStyleKnockoutBlower blower; blower.setKnockoutSelection(knockoutSelection); blower.apply(painter, sourceProjection, rect); + + blower.resetKnockoutSelection(); } else { sourcePlane->apply(painter, rect); } Q_FOREACH (KisLayerStyleFilterProjectionPlaneSP plane, m_d->stylesAfter) { m_d->applyComplexPlane(painter, plane, rect, originalClone); } } else { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesBefore) { plane->apply(painter, rect); } sourcePlane->apply(painter, rect); Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->stylesAfter) { plane->apply(painter, rect); } } } else { sourcePlane->apply(painter, rect); } } KisPaintDeviceList KisLayerStyleProjectionPlane::getLodCapableDevices() const { KisPaintDeviceList list; KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { list << plane->getLodCapableDevices(); } list << sourcePlane->getLodCapableDevices(); } else { list << sourcePlane->getLodCapableDevices(); } return list; } QRect KisLayerStyleProjectionPlane::needRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { /** * Need rect should also be adjust for the layers that generate their 'original' * based on the contents of the underlying layers like KisAdjustmentLayer * * \see bug 390299 */ QRect needRect = rect; const bool adjustmentAboveDirty = m_d->dependsOnLowerNodes && (pos & KisLayer::N_FILTHY || pos & KisLayer::N_ABOVE_FILTHY); if (m_d->style->isEnabled() && adjustmentAboveDirty) { needRect |= stylesNeedRect(rect); } KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); needRect = sourcePlane->needRect(needRect, pos); return needRect; } QRect KisLayerStyleProjectionPlane::changeRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect layerChangeRect = sourcePlane->changeRect(rect, pos); QRect changeRect = layerChangeRect; if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { changeRect |= plane->changeRect(layerChangeRect, KisLayer::N_ABOVE_FILTHY); } } return changeRect; } QRect KisLayerStyleProjectionPlane::accessRect(const QRect &rect, KisLayer::PositionToFilthy pos) const { KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); QRect accessRect = sourcePlane->accessRect(rect, pos); if (m_d->style->isEnabled()) { Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { accessRect |= plane->accessRect(rect, KisLayer::N_ABOVE_FILTHY); } } return accessRect; } QRect KisLayerStyleProjectionPlane::needRectForOriginal(const QRect &rect) const { /** * Need rect should also be adjust for the layers that generate their 'original' * based on the contents of the child layers like KisGroupLayer * * \see bug 366419 */ QRect needRect = rect; if (m_d->style->isEnabled()) { needRect |= stylesNeedRect(needRect); } KisAbstractProjectionPlaneSP sourcePlane = m_d->sourceProjectionPlane.toStrongRef(); needRect = sourcePlane->needRectForOriginal(needRect); return needRect; } QRect KisLayerStyleProjectionPlane::stylesNeedRect(const QRect &rect) const { QRect needRect = rect; Q_FOREACH (const KisAbstractProjectionPlaneSP plane, m_d->allStyles()) { needRect |= plane->needRect(rect, KisLayer::N_ABOVE_FILTHY); } return needRect; } diff --git a/libs/image/layerstyles/kis_ls_stroke_filter.cpp b/libs/image/layerstyles/kis_ls_stroke_filter.cpp index 5d6f4bf002..db94fec07c 100644 --- a/libs/image/layerstyles/kis_ls_stroke_filter.cpp +++ b/libs/image/layerstyles/kis_ls_stroke_filter.cpp @@ -1,174 +1,171 @@ /* * Copyright (c) 2014 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_ls_stroke_filter.h" #include #include #include #include #include "psd.h" #include "kis_convolution_kernel.h" #include "kis_convolution_painter.h" #include "kis_gaussian_kernel.h" #include "kis_pixel_selection.h" #include "kis_fill_painter.h" #include "kis_gradient_painter.h" #include "kis_iterator_ng.h" #include "kis_random_accessor_ng.h" #include "kis_psd_layer_style.h" #include "kis_layer_style_filter_environment.h" #include "kis_ls_utils.h" #include "kis_multiple_projection.h" #include "kis_cached_paint_device.h" #include "krita_utils.h" #include "KisLayerStyleKnockoutBlower.h" namespace { int borderSize(psd_stroke_position position, int size) { int border = 0; switch (position) { case psd_stroke_outside: border = size + 1; break; case psd_stroke_center: border = qCeil(0.5 * size) + 1; break; case psd_stroke_inside: border = 1; break; } return border; } } KisLsStrokeFilter::KisLsStrokeFilter() : KisLayerStyleFilter(KoID("lsstroke", i18n("Stroke (style)"))) { } KisLsStrokeFilter::KisLsStrokeFilter(const KisLsStrokeFilter &rhs) : KisLayerStyleFilter(rhs) { } KisLayerStyleFilter *KisLsStrokeFilter::clone() const { return new KisLsStrokeFilter(*this); } void KisLsStrokeFilter::applyStroke(KisPaintDeviceSP srcDevice, KisMultipleProjection *dst, KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, const psd_layer_effects_stroke *config, KisLayerStyleFilterEnvironment *env) const { if (applyRect.isEmpty()) return; const QRect needRect = kisGrowRect(applyRect, borderSize(config->position(), config->size())); - KisSelectionSP baseSelection = blower->knockoutSelection(); - if (!baseSelection) { - baseSelection = new KisSelection(new KisSelectionEmptyBounds(0)); - blower->setKnockoutSelection(baseSelection); - } + KisSelectionSP baseSelection = blower->knockoutSelectionLazy(); + KisLsUtils::selectionFromAlphaChannel(srcDevice, baseSelection, needRect); KisPixelSelectionSP selection = baseSelection->pixelSelection(); // KritaUtils::filterAlpha8Device(selection, needRect, // [](quint8 pixel) { // return pixel > 0 ? 255 : 0; // }); // KisGaussianKernel::applyGaussian(selection, needRect, 1.0, 1.0, QBitArray(), 0); { KisCachedSelection::Guard s2(*env->cachedSelection()); KisPixelSelectionSP knockOutSelection = s2.selection()->pixelSelection(); knockOutSelection->makeCloneFromRough(selection, needRect); if (config->position() == psd_stroke_outside) { KisGaussianKernel::applyDilate(selection, needRect, config->size(), QBitArray(), 0, true); } else if (config->position() == psd_stroke_inside) { KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, config->size(), QBitArray(), 0, true); } else if (config->position() == psd_stroke_center) { KisGaussianKernel::applyDilate(selection, needRect, 0.5 * config->size(), QBitArray(), 0, true); KisGaussianKernel::applyErodeU8(knockOutSelection, needRect, 0.5 * config->size(), QBitArray(), 0, true); } KisPainter gc(selection); gc.setCompositeOp(COMPOSITE_ERASE); gc.bitBlt(needRect.topLeft(), knockOutSelection, needRect); gc.end(); } const QString compositeOp = config->blendMode(); const quint8 opacityU8 = quint8(qRound(255.0 / 100.0 * config->opacity())); KisPaintDeviceSP dstDevice = dst->getProjection(KisMultipleProjection::defaultProjectionId(), compositeOp, opacityU8, QBitArray(), srcDevice); KisLsUtils::fillOverlayDevice(dstDevice, applyRect, config, env); } void KisLsStrokeFilter::processDirectly(KisPaintDeviceSP src, KisMultipleProjection *dst, KisLayerStyleKnockoutBlower *blower, const QRect &applyRect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { Q_UNUSED(env); KIS_ASSERT_RECOVER_RETURN(style); const psd_layer_effects_stroke *config = style->stroke(); if (!KisLsUtils::checkEffectEnabled(config, dst)) return; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); applyStroke(src, dst, blower, applyRect, w.config, env); } QRect KisLsStrokeFilter::neededRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { const psd_layer_effects_stroke *config = style->stroke(); if (!config->effectEnabled()) return rect; KisLsUtils::LodWrapper w(env->currentLevelOfDetail(), config); return kisGrowRect(rect, borderSize(w.config->position(), w.config->size())); } QRect KisLsStrokeFilter::changedRect(const QRect &rect, KisPSDLayerStyleSP style, KisLayerStyleFilterEnvironment *env) const { return neededRect(rect, style, env); }