Commit 029deeef authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implement proper compression for the filter dialog

The patch consists of three different changes:

1) CancelSilentlyMarker is changed from a job to an atomic flag.
   Before this change, the job used to be cancelled before the
   actual flag was reset. It caused too many unnecessary updates
   to happen.

2) KisFilterStrokeStrategy now provides a cookie to show whether
   the procesing has finished or not.

3) This cookie is used in a new mode in KisSignalCompressor. This
   mode works as the normal FIRST_ACTIVE mode, with one exception:
   it has "the second" shorter timer that checks if the queue is
   already idle. If it is idle, then the signal will be passed
   before the normal deadline. This mode is activated by calling
   the second override of setDelay() that accepts isIdle callback
   for the state of the queue.
parent fe691e04
...@@ -58,8 +58,7 @@ KisSignalCompressor::KisSignalCompressor(int delay, Mode mode, SlowHandlerMode s ...@@ -58,8 +58,7 @@ KisSignalCompressor::KisSignalCompressor(int delay, Mode mode, SlowHandlerMode s
connect(m_timer, SIGNAL(timeout()), SLOT(slotTimerExpired())); connect(m_timer, SIGNAL(timeout()), SLOT(slotTimerExpired()));
} }
void KisSignalCompressor::setDelayImpl(int delay)
void KisSignalCompressor::setDelay(int delay)
{ {
const bool wasActive = m_timer->isActive(); const bool wasActive = m_timer->isActive();
...@@ -74,6 +73,20 @@ void KisSignalCompressor::setDelay(int delay) ...@@ -74,6 +73,20 @@ void KisSignalCompressor::setDelay(int delay)
} }
} }
void KisSignalCompressor::setDelay(int delay)
{
m_timeout = delay;
m_idleCallback = {};
setDelayImpl(delay);
}
void KisSignalCompressor::setDelay(std::function<bool ()> idleCallback, int idleDelay, int timeout)
{
m_timeout = timeout;
m_idleCallback = idleCallback;
setDelayImpl(idleDelay);
}
void KisSignalCompressor::start() void KisSignalCompressor::start()
{ {
KIS_SAFE_ASSERT_RECOVER_RETURN(m_mode != UNDEFINED); KIS_SAFE_ASSERT_RECOVER_RETURN(m_mode != UNDEFINED);
...@@ -138,13 +151,16 @@ bool KisSignalCompressor::tryEmitOnTick(bool isFromTimer) ...@@ -138,13 +151,16 @@ bool KisSignalCompressor::tryEmitOnTick(bool isFromTimer)
// we have different requirements for hi-frequency events (the mean // we have different requirements for hi-frequency events (the mean
// of the events rate must be min(compressorRate, eventsRate) // of the events rate must be min(compressorRate, eventsRate)
const int realInterval = m_timer->interval(); const int realInterval = m_timeout;
const int minInterval = realInterval < 100 ? 0.5 * realInterval : realInterval; const int minInterval = realInterval < 100 ? 0.5 * realInterval : realInterval;
// Enable for debugging: // Enable for debugging:
// ENTER_FUNCTION() << ppVar(isFromTimer) << ppVar(m_signalsPending) << m_lastEmittedTimer.elapsed(); // ENTER_FUNCTION() << ppVar(isFromTimer) << ppVar(m_signalsPending) << m_lastEmittedTimer.elapsed() << ppVar((m_idleCallback && m_idleCallback()));
if (m_signalsPending &&
(m_lastEmittedTimer.elapsed() >= minInterval ||
(m_idleCallback && m_idleCallback()))) {
if (m_signalsPending && m_lastEmittedTimer.elapsed() >= minInterval) {
KIS_SAFE_ASSERT_RECOVER_NOOP(!isFromTimer || !m_isEmitting); KIS_SAFE_ASSERT_RECOVER_NOOP(!isFromTimer || !m_isEmitting);
if (m_slowHandlerMode == PRECISE_INTERVAL) { if (m_slowHandlerMode == PRECISE_INTERVAL) {
...@@ -188,7 +204,7 @@ void KisSignalCompressor::slotTimerExpired() ...@@ -188,7 +204,7 @@ void KisSignalCompressor::slotTimerExpired()
{ {
KIS_ASSERT_RECOVER_NOOP(m_mode != UNDEFINED); KIS_ASSERT_RECOVER_NOOP(m_mode != UNDEFINED);
if (!tryEmitOnTick(true)) { if (!tryEmitOnTick(true)) {
const int calmDownInterval = 5 * m_timer->interval(); const int calmDownInterval = 5 * m_timeout;
if (!m_lastEmittedTimer.isValid() || if (!m_lastEmittedTimer.isValid() ||
m_lastEmittedTimer.elapsed() > calmDownInterval) { m_lastEmittedTimer.elapsed() > calmDownInterval) {
...@@ -217,5 +233,5 @@ void KisSignalCompressor::setMode(KisSignalCompressor::Mode mode) ...@@ -217,5 +233,5 @@ void KisSignalCompressor::setMode(KisSignalCompressor::Mode mode)
int KisSignalCompressor::delay() const int KisSignalCompressor::delay() const
{ {
return m_timer->interval(); return m_timeout;
} }
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "kritaglobal_export.h" #include "kritaglobal_export.h"
#include <QElapsedTimer> #include <QElapsedTimer>
#include <functional>
class QTimer; class QTimer;
...@@ -71,6 +72,8 @@ public: ...@@ -71,6 +72,8 @@ public:
int delay() const; int delay() const;
void setIdleCallback();
void setDelay(std::function<bool()> idleCallback, int idleDelay, int timeout);
public Q_SLOTS: public Q_SLOTS:
void setDelay(int delay); void setDelay(int delay);
...@@ -86,6 +89,7 @@ Q_SIGNALS: ...@@ -86,6 +89,7 @@ Q_SIGNALS:
private: private:
bool tryEmitOnTick(bool isFromTimer); bool tryEmitOnTick(bool isFromTimer);
bool tryEmitSignalSafely(); bool tryEmitSignalSafely();
void setDelayImpl(int delay);
private: private:
QTimer *m_timer = 0; QTimer *m_timer = 0;
...@@ -94,6 +98,8 @@ private: ...@@ -94,6 +98,8 @@ private:
bool m_signalsPending = false; bool m_signalsPending = false;
QElapsedTimer m_lastEmittedTimer; QElapsedTimer m_lastEmittedTimer;
int m_isEmitting = 0; int m_isEmitting = 0;
int m_timeout = 0;
std::function<bool()> m_idleCallback;
}; };
#endif /* __KIS_SIGNAL_COMPRESSOR_H */ #endif /* __KIS_SIGNAL_COMPRESSOR_H */
...@@ -115,6 +115,59 @@ void KisSignalCompressorTest::testSlowHandlerAdditive() ...@@ -115,6 +115,59 @@ void KisSignalCompressorTest::testSlowHandlerAdditive()
} }
} }
void testIdleChecksImpl(int compressorInterval,
int timerInterval,
int idleCheckInterval,
int idleDelay)
{
const int handlerDelay = 0;
QElapsedTimer elapsedTimer;
elapsedTimer.start();
CompressorTester tester(handlerDelay);
KisSignalCompressor compressor(compressorInterval,
KisSignalCompressor::FIRST_ACTIVE,
KisSignalCompressor::PRECISE_INTERVAL);
compressor.setDelay(
[idleDelay, &elapsedTimer]() {
return elapsedTimer.elapsed() > idleDelay;
},
idleCheckInterval,
compressorInterval);
QTimer timer;
timer.setInterval(timerInterval);
timer.setTimerType(Qt::PreciseTimer);
timer.setSingleShot(false);
QObject::connect(&timer, SIGNAL(timeout()), &compressor, SLOT(start()));
QObject::connect(&compressor, SIGNAL(timeout()), &tester, SLOT(start()));
QObject::connect(&compressor, &KisSignalCompressor::timeout,
[&elapsedTimer] () { elapsedTimer.restart(); });
timer.start();
QTest::qWait(500);
timer.stop();
QTest::qWait(compressorInterval * 2);
compressor.stop();
tester.dump(QString("timer %1 compressor %2 idle check %3 idle delay %4")
.arg(timerInterval).arg(compressorInterval)
.arg(idleCheckInterval).arg(idleDelay));
QTest::qWait(compressorInterval * 10);
}
void KisSignalCompressorTest::testIdleChecks()
{
for (int i = 0; i < 40; i += 3) {
testIdleChecksImpl(50, 5, 5, qMax(1, i));
}
}
QTEST_MAIN(KisSignalCompressorTest) QTEST_MAIN(KisSignalCompressorTest)
......
...@@ -18,6 +18,7 @@ private Q_SLOTS: ...@@ -18,6 +18,7 @@ private Q_SLOTS:
void test(); void test();
void testSlowHandlerPrecise(); void testSlowHandlerPrecise();
void testSlowHandlerAdditive(); void testSlowHandlerAdditive();
void testIdleChecks();
}; };
#endif // KISSIGNALCOMPRESSORTEST_H #endif // KISSIGNALCOMPRESSORTEST_H
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include "kis_filter_manager.h" #include "kis_filter_manager.h"
#include "ui_wdgfilterdialog.h" #include "ui_wdgfilterdialog.h"
#include "kis_canvas2.h" #include "kis_canvas2.h"
#include "kis_signal_compressor.h"
struct KisDlgFilter::Private { struct KisDlgFilter::Private {
Private(KisFilterManager *_filterManager, KisViewManager *_view) Private(KisFilterManager *_filterManager, KisViewManager *_view)
...@@ -34,7 +34,13 @@ struct KisDlgFilter::Private { ...@@ -34,7 +34,13 @@ struct KisDlgFilter::Private {
, view(_view) , view(_view)
, filterManager(_filterManager) , filterManager(_filterManager)
, blockModifyingActionsGuard(new KisInputActionGroupsMaskGuard(view->canvasBase(), ViewTransformActionGroup)) , blockModifyingActionsGuard(new KisInputActionGroupsMaskGuard(view->canvasBase(), ViewTransformActionGroup))
, updateCompressor(200, KisSignalCompressor::FIRST_ACTIVE)
{ {
updateCompressor.setDelay(
[this] () {
return filterManager->isIdle();
},
20, 200);
} }
KisFilterSP currentFilter; KisFilterSP currentFilter;
...@@ -47,6 +53,7 @@ struct KisDlgFilter::Private { ...@@ -47,6 +53,7 @@ struct KisDlgFilter::Private {
// a special guard object that blocks all the painting input actions while the // a special guard object that blocks all the painting input actions while the
// dialog is open // dialog is open
QScopedPointer<KisInputActionGroupsMaskGuard> blockModifyingActionsGuard; QScopedPointer<KisInputActionGroupsMaskGuard> blockModifyingActionsGuard;
KisSignalCompressor updateCompressor;
}; };
KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManager *filterManager, QWidget *parent) : KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManager *filterManager, QWidget *parent) :
...@@ -92,6 +99,7 @@ KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManage ...@@ -92,6 +99,7 @@ KisDlgFilter::KisDlgFilter(KisViewManager *view, KisNodeSP node, KisFilterManage
d->uiFilterDialog.checkBoxPreview->setChecked(group.readEntry("showPreview", true)); d->uiFilterDialog.checkBoxPreview->setChecked(group.readEntry("showPreview", true));
restoreGeometry(KisConfig(true).readEntry("filterdialog/geometry", QByteArray())); restoreGeometry(KisConfig(true).readEntry("filterdialog/geometry", QByteArray()));
connect(&d->updateCompressor, SIGNAL(timeout()), this, SLOT(updatePreview()));
} }
...@@ -108,7 +116,7 @@ void KisDlgFilter::setFilter(KisFilterSP f, KisFilterConfigurationSP overrideDef ...@@ -108,7 +116,7 @@ void KisDlgFilter::setFilter(KisFilterSP f, KisFilterConfigurationSP overrideDef
d->uiFilterDialog.filterSelection->setFilter(f, overrideDefaultConfig); d->uiFilterDialog.filterSelection->setFilter(f, overrideDefaultConfig);
d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(f->supportsAdjustmentLayers()); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(f->supportsAdjustmentLayers());
d->currentFilter = f; d->currentFilter = f;
updatePreview(); d->updateCompressor.start();
} }
void KisDlgFilter::setDialogTitle(KisFilterSP filter) void KisDlgFilter::setDialogTitle(KisFilterSP filter)
...@@ -199,7 +207,7 @@ void KisDlgFilter::createMask() ...@@ -199,7 +207,7 @@ void KisDlgFilter::createMask()
void KisDlgFilter::enablePreviewToggled(bool state) void KisDlgFilter::enablePreviewToggled(bool state)
{ {
if (state) { if (state) {
updatePreview(); d->updateCompressor.start();
} else if (d->filterManager->isStrokeRunning()) { } else if (d->filterManager->isStrokeRunning()) {
d->filterManager->cancel(); d->filterManager->cancel();
} }
...@@ -216,7 +224,7 @@ void KisDlgFilter::filterSelectionChanged() ...@@ -216,7 +224,7 @@ void KisDlgFilter::filterSelectionChanged()
setDialogTitle(filter); setDialogTitle(filter);
d->currentFilter = filter; d->currentFilter = filter;
d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(filter.isNull() ? false : filter->supportsAdjustmentLayers()); d->uiFilterDialog.pushButtonCreateMaskEffect->setEnabled(filter.isNull() ? false : filter->supportsAdjustmentLayers());
updatePreview(); d->updateCompressor.start();
} }
......
...@@ -46,10 +46,11 @@ public Q_SLOTS: ...@@ -46,10 +46,11 @@ public Q_SLOTS:
private: private:
void startApplyingFilter(KisFilterConfigurationSP config); void startApplyingFilter(KisFilterConfigurationSP config);
void setDialogTitle(KisFilterSP f); void setDialogTitle(KisFilterSP f);
void updatePreview();
private Q_SLOTS: private Q_SLOTS:
void slotFilterWidgetSizeChanged(); void slotFilterWidgetSizeChanged();
void updatePreview();
private: private:
struct Private; struct Private;
......
...@@ -59,6 +59,8 @@ struct KisFilterManager::Private { ...@@ -59,6 +59,8 @@ struct KisFilterManager::Private {
KisFilterConfigurationSP lastConfiguration; KisFilterConfigurationSP lastConfiguration;
KisFilterConfigurationSP currentlyAppliedConfiguration; KisFilterConfigurationSP currentlyAppliedConfiguration;
KisStrokeId currentStrokeId; KisStrokeId currentStrokeId;
QSharedPointer<QAtomicInt> cancelSilentlyHandle;
KisFilterStrokeStrategy::IdleBarrierData::IdleBarrierCookie idleBarrierCookie;
QRect initialApplyRect; QRect initialApplyRect;
QRect currentProcessRect; QRect currentProcessRect;
...@@ -270,9 +272,12 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig) ...@@ -270,9 +272,12 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig)
KisImageWSP image = d->view->image(); KisImageWSP image = d->view->image();
if (d->currentStrokeId) { if (d->currentStrokeId) {
image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::CancelSilentlyMarker); d->cancelSilentlyHandle->ref();
image->cancelStroke(d->currentStrokeId); image->cancelStroke(d->currentStrokeId);
d->currentStrokeId.clear(); d->currentStrokeId.clear();
d->cancelSilentlyHandle.clear();
d->idleBarrierCookie.clear();
} else { } else {
image->waitForDone(); image->waitForDone();
d->initialApplyRect = d->view->activeNode()->exactBounds(); d->initialApplyRect = d->view->activeNode()->exactBounds();
...@@ -295,13 +300,14 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig) ...@@ -295,13 +300,14 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig)
d->view->activeNode(), d->view->activeNode(),
resourceManager); resourceManager);
KisStrokeStrategy *strategy = new KisFilterStrokeStrategy(filter, KisFilterStrokeStrategy *strategy = new KisFilterStrokeStrategy(filter,
KisFilterConfigurationSP(filterConfig), KisFilterConfigurationSP(filterConfig),
resources); resources);
{ {
KConfigGroup group( KSharedConfig::openConfig(), "filterdialog"); KConfigGroup group( KSharedConfig::openConfig(), "filterdialog");
strategy->setForceLodModeIfPossible(group.readEntry("forceLodMode", true)); strategy->setForceLodModeIfPossible(group.readEntry("forceLodMode", true));
} }
d->cancelSilentlyHandle = strategy->cancelSilentlyHandle();
d->currentStrokeId = d->currentStrokeId =
image->startStroke(strategy); image->startStroke(strategy);
...@@ -322,6 +328,13 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig) ...@@ -322,6 +328,13 @@ void KisFilterManager::apply(KisFilterConfigurationSP _filterConfig)
new KisFilterStrokeStrategy::Data(processRect, false)); new KisFilterStrokeStrategy::Data(processRect, false));
} }
{
KisFilterStrokeStrategy::IdleBarrierData *data =
new KisFilterStrokeStrategy::IdleBarrierData();
d->idleBarrierCookie = data->idleBarrierCookie();
image->addJob(d->currentStrokeId, data);
}
QRegion extraUpdateRegion(d->currentProcessRect); QRegion extraUpdateRegion(d->currentProcessRect);
extraUpdateRegion -= processRect; extraUpdateRegion -= processRect;
...@@ -355,6 +368,8 @@ void KisFilterManager::finish() ...@@ -355,6 +368,8 @@ void KisFilterManager::finish()
d->reapplyAction->setText(i18n("Apply Filter Again: %1", filter->name())); d->reapplyAction->setText(i18n("Apply Filter Again: %1", filter->name()));
d->currentStrokeId.clear(); d->currentStrokeId.clear();
d->cancelSilentlyHandle.clear();
d->idleBarrierCookie.clear();
d->currentlyAppliedConfiguration.clear(); d->currentlyAppliedConfiguration.clear();
d->currentProcessRect = QRect(); d->currentProcessRect = QRect();
} }
...@@ -366,6 +381,8 @@ void KisFilterManager::cancel() ...@@ -366,6 +381,8 @@ void KisFilterManager::cancel()
d->view->image()->cancelStroke(d->currentStrokeId); d->view->image()->cancelStroke(d->currentStrokeId);
d->currentStrokeId.clear(); d->currentStrokeId.clear();
d->cancelSilentlyHandle.clear();
d->idleBarrierCookie.clear();
d->currentlyAppliedConfiguration.clear(); d->currentlyAppliedConfiguration.clear();
d->currentProcessRect = QRect(); d->currentProcessRect = QRect();
} }
...@@ -375,6 +392,11 @@ bool KisFilterManager::isStrokeRunning() const ...@@ -375,6 +392,11 @@ bool KisFilterManager::isStrokeRunning() const
return d->currentStrokeId; return d->currentStrokeId;
} }
bool KisFilterManager::isIdle() const
{
return !d->idleBarrierCookie;
}
void KisFilterManager::slotStrokeEndRequested() void KisFilterManager::slotStrokeEndRequested()
{ {
if (d->currentStrokeId && d->filterDialog) { if (d->currentStrokeId && d->filterDialog) {
......
...@@ -39,6 +39,8 @@ public: ...@@ -39,6 +39,8 @@ public:
void cancel(); void cancel();
bool isStrokeRunning() const; bool isStrokeRunning() const;
bool isIdle() const;
private Q_SLOTS: private Q_SLOTS:
void insertFilter(const QString &name); void insertFilter(const QString &name);
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
struct KisFilterStrokeStrategy::Private { struct KisFilterStrokeStrategy::Private {
Private() Private()
: updatesFacade(0), : updatesFacade(0),
cancelSilently(false),
secondaryTransaction(0), secondaryTransaction(0),
cancelSilentlyHandle(new QAtomicInt()),
levelOfDetail(0) levelOfDetail(0)
{ {
} }
...@@ -26,11 +26,11 @@ struct KisFilterStrokeStrategy::Private { ...@@ -26,11 +26,11 @@ struct KisFilterStrokeStrategy::Private {
filterConfig(rhs.filterConfig), filterConfig(rhs.filterConfig),
node(rhs.node), node(rhs.node),
updatesFacade(rhs.updatesFacade), updatesFacade(rhs.updatesFacade),
cancelSilently(rhs.cancelSilently),
filterDevice(), filterDevice(),
filterDeviceBounds(), filterDeviceBounds(),
secondaryTransaction(0), secondaryTransaction(0),
progressHelper(), progressHelper(),
cancelSilentlyHandle(rhs.cancelSilentlyHandle),
levelOfDetail(0) levelOfDetail(0)
{ {
KIS_ASSERT_RECOVER_RETURN(!rhs.filterDevice); KIS_ASSERT_RECOVER_RETURN(!rhs.filterDevice);
...@@ -45,11 +45,11 @@ struct KisFilterStrokeStrategy::Private { ...@@ -45,11 +45,11 @@ struct KisFilterStrokeStrategy::Private {
KisNodeSP node; KisNodeSP node;
KisUpdatesFacade *updatesFacade; KisUpdatesFacade *updatesFacade;
bool cancelSilently;
KisPaintDeviceSP filterDevice; KisPaintDeviceSP filterDevice;
QRect filterDeviceBounds; QRect filterDeviceBounds;
KisTransaction *secondaryTransaction; KisTransaction *secondaryTransaction;
QScopedPointer<KisProcessingVisitor::ProgressHelper> progressHelper; QScopedPointer<KisProcessingVisitor::ProgressHelper> progressHelper;
QSharedPointer<QAtomicInt> cancelSilentlyHandle;
int levelOfDetail; int levelOfDetail;
}; };
...@@ -68,7 +68,6 @@ KisFilterStrokeStrategy::KisFilterStrokeStrategy(KisFilterSP filter, ...@@ -68,7 +68,6 @@ KisFilterStrokeStrategy::KisFilterStrokeStrategy(KisFilterSP filter,
m_d->filterConfig = filterConfig; m_d->filterConfig = filterConfig;
m_d->node = resources->currentNode(); m_d->node = resources->currentNode();
m_d->updatesFacade = resources->image().data(); m_d->updatesFacade = resources->image().data();
m_d->cancelSilently = false;
m_d->secondaryTransaction = 0; m_d->secondaryTransaction = 0;
m_d->levelOfDetail = 0; m_d->levelOfDetail = 0;
...@@ -121,8 +120,6 @@ void KisFilterStrokeStrategy::initStrokeCallback() ...@@ -121,8 +120,6 @@ void KisFilterStrokeStrategy::initStrokeCallback()
void KisFilterStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) void KisFilterStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
{ {
Data *d = dynamic_cast<Data*>(data); Data *d = dynamic_cast<Data*>(data);
CancelSilentlyMarker *cancelJob =
dynamic_cast<CancelSilentlyMarker*>(data);
ExtraCleanUpUpdates *cleanup = dynamic_cast<ExtraCleanUpUpdates*>(data); ExtraCleanUpUpdates *cleanup = dynamic_cast<ExtraCleanUpUpdates*>(data);
if (d) { if (d) {
...@@ -146,10 +143,10 @@ void KisFilterStrokeStrategy::doStrokeCallback(KisStrokeJobData *data) ...@@ -146,10 +143,10 @@ void KisFilterStrokeStrategy::doStrokeCallback(KisStrokeJobData *data)
} }
m_d->node->setDirty(rc); m_d->node->setDirty(rc);
} else if (cancelJob) {
m_d->cancelSilently = true;
} else if (cleanup) { } else if (cleanup) {
m_d->node->setDirty(cleanup->rects); m_d->node->setDirty(cleanup->rects);
} else if (dynamic_cast<IdleBarrierData*>(data)) {
/* noop, just delete that */
} else { } else {
qFatal("KisFilterStrokeStrategy: job type is not known"); qFatal("KisFilterStrokeStrategy: job type is not known");
} }
...@@ -160,13 +157,15 @@ void KisFilterStrokeStrategy::cancelStrokeCallback() ...@@ -160,13 +157,15 @@ void KisFilterStrokeStrategy::cancelStrokeCallback()
delete m_d->secondaryTransaction; delete m_d->secondaryTransaction;
m_d->filterDevice = 0; m_d->filterDevice = 0;
if (m_d->cancelSilently) { const bool shouldCancelSilently = *m_d->cancelSilentlyHandle;
if (shouldCancelSilently) {
m_d->updatesFacade->disableDirtyRequests(); m_d->updatesFacade->disableDirtyRequests();
} }
KisPainterBasedStrokeStrategy::cancelStrokeCallback(); KisPainterBasedStrokeStrategy::cancelStrokeCallback();
if (m_d->cancelSilently) { if (shouldCancelSilently) {
m_d->updatesFacade->enableDirtyRequests(); m_d->updatesFacade->enableDirtyRequests();
} }
} }
...@@ -187,3 +186,8 @@ KisStrokeStrategy* KisFilterStrokeStrategy::createLodClone(int levelOfDetail) ...@@ -187,3 +186,8 @@ KisStrokeStrategy* KisFilterStrokeStrategy::createLodClone(int levelOfDetail)
KisFilterStrokeStrategy *clone = new KisFilterStrokeStrategy(*this, levelOfDetail); KisFilterStrokeStrategy *clone = new KisFilterStrokeStrategy(*this, levelOfDetail);
return clone; return clone;
} }