Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_transform_mask.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
3 *
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include <QMutex>
9#include <QMutexLocker>
10#include <KoIcon.h>
11#include <kis_icon.h>
13
14#include "kis_layer.h"
15#include "kis_transform_mask.h"
16#include <kis_group_layer.h>
17#include "filter/kis_filter.h"
20#include "kis_selection.h"
22#include "kis_node.h"
23#include "kis_node_visitor.h"
26#include "kis_painter.h"
27
34#include "kis_algebra_2d.h"
35#include "kis_safe_transform.h"
39
40#include "kis_image_config.h"
42
43#include <QReadWriteLock>
45
46//#include "kis_paint_device_debug_utils.h"
47//#define DEBUG_RENDERING
48//#define DUMP_RECT QRect(0,0,512,512)
49
50namespace {
51
52class StaticCacheStorage
53{
54public:
55 bool isCacheValid(KisTransformMaskParamsInterfaceSP currentParams) const {
56 QReadLocker l(&m_lock);
57
58 KIS_SAFE_ASSERT_RECOVER_NOOP(!staticCacheValid ||
59 paramsForStaticImage ||
60 staticCacheIsOverridden);
61
62 return staticCacheValid &&
63 (!paramsForStaticImage ||
64 paramsForStaticImage->compareTransform(currentParams));
65 }
66
67 bool isCacheOverridden() const {
68 QReadLocker l(&m_lock);
69
70 KIS_SAFE_ASSERT_RECOVER_NOOP(!staticCacheIsOverridden || staticCacheValid);
71
72 return staticCacheIsOverridden;
73 }
74
75 void lazyAllocateStaticCache(const KoColorSpace *cs, KisDefaultBoundsBaseSP defaultBounds) {
76 QWriteLocker l(&m_lock);
77
78 if (!staticCacheDevice ||
79 *staticCacheDevice->colorSpace() != *cs) {
80
81 staticCacheDevice = new KisPaintDevice(cs);
82 staticCacheDevice->setDefaultBounds(defaultBounds);
83 }
84 }
85
86 KisPaintDeviceSP device() {
87 return staticCacheDevice;
88 }
89
90 void setDeviceCacheValid(KisTransformMaskParamsInterfaceSP currentParams) {
91 QWriteLocker l(&m_lock);
92
93 paramsForStaticImage = currentParams;
94 staticCacheValid = true;
95 KIS_SAFE_ASSERT_RECOVER_NOOP(!staticCacheIsOverridden);
96 }
97
98 void overrideStaticCacheDevice(KisPaintDeviceSP device)
99 {
100 KIS_SAFE_ASSERT_RECOVER_RETURN(staticCacheDevice);
101
102 staticCacheDevice->clear();
103
104 if (device) {
105 const QRect rc = device->extent();
106 KisPainter::copyAreaOptimized(rc.topLeft(), device, staticCacheDevice, rc);
107 }
108
109 {
110 QWriteLocker l(&m_lock);
111 paramsForStaticImage.clear();
112 staticCacheValid = bool(device);
113 staticCacheIsOverridden = bool(device);
114 }
115 }
116
117 void invalidateDeviceCache() {
118 staticCacheValid = false;
119 paramsForStaticImage.clear();
120 KIS_SAFE_ASSERT_RECOVER_NOOP(!staticCacheIsOverridden);
121 }
122
123private:
124 mutable QReadWriteLock m_lock;
125 bool staticCacheIsOverridden {false};
126 bool staticCacheValid = {false};
127 KisPaintDeviceSP staticCacheDevice;
128 KisTransformMaskParamsInterfaceSP paramsForStaticImage;
129};
130
131struct AccumulatedRectStorage
132{
133 void addRect(const QRect &rc) {
134 QMutexLocker l(&m_mutex);
135 m_rect |= rc;
136 }
137
138 QRect takeRect() {
139 QMutexLocker l(&m_mutex);
140
141 const QRect rect = m_rect;
142 m_rect = QRect();
143
144 return rect;
145 }
146
147private:
148 QMutex m_mutex;
149 QRect m_rect;
150};
151
152}
153
154#define UPDATE_DELAY 3000 /*ms */
155
156struct Q_DECL_HIDDEN KisTransformMask::Private
157{
159 : worker(0, QTransform(), true, 0),
160 paramsHolder(KisTransformMaskParamsFactoryRegistry::instance()->createAnimatedParamsHolder(new KisDefaultBounds(image))),
161 recalculatingStaticImage(false),
162 offset(new KisDefaultBounds(image)),
163 updateSignalCompressor(UPDATE_DELAY, KisSignalCompressor::POSTPONE),
164 offBoundsReadArea(0.5)
165 {
166 }
167
168 Private(const Private &rhs)
169 : worker(rhs.worker),
170 paramsHolder(rhs.paramsHolder->clone()),
171 recalculatingStaticImage(rhs.recalculatingStaticImage),
172 offset(rhs.offset),
173 updateSignalCompressor(UPDATE_DELAY, KisSignalCompressor::POSTPONE),
174 offBoundsReadArea(rhs.offBoundsReadArea)
175 {
176 }
177
180
181 StaticCacheStorage staticCache;
183
184 AccumulatedRectStorage forcedStaticUpdateExtraUpdateRect;
185
187
190
191 QScopedPointer<KisTransformMaskTestingInterface> testingInterface;
192};
193
194
196 : KisEffectMask(image, name),
197 m_d(new Private(image))
198{
199 connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDelayedStaticUpdate()));
201 m_d->offBoundsReadArea = KisImageConfig(true).transformMaskOffBoundsReadArea();
202 setSupportsLodMoves(false);
203}
204
208
210 : KisEffectMask(rhs),
211 m_d(new Private(*rhs.m_d))
212{
213 connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDelayedStaticUpdate()));
214
215
229
230 Q_FOREACH (const QString &id, ids) {
231 KisKeyframeChannel *channel = m_d->paramsHolder->getKeyframeChannel(id);
232 if (channel) {
233 addKeyframeChannel(channel);
234 }
235 }
236}
237
239{
240 return 0;
241}
242
244{
245 return KisIconUtils::loadIcon("transformMask");
246}
247
249{
251
252 m_d->paramsHolder->setParamsAtCurrentPosition(params.data(), parentCommand);
253}
254
256{
257 KUndo2Command todo_REMOVE;
258 setTransformParamsWithUndo(params, &todo_REMOVE);
259 todo_REMOVE.redo();
260
261 m_d->staticCache.invalidateDeviceCache();
262 m_d->updateSignalCompressor.start();
263}
264
266{
267 return m_d->paramsHolder->bakeIntoParams();
268}
269
271{
272 if (m_d->testingInterface) {
273 m_d->testingInterface->notifySlotDelayedStaticUpdate();
274 }
275
277}
278
280{
281 m_d->staticCache.invalidateDeviceCache();
282 m_d->updateSignalCompressor.stop();
284}
285
287{
293 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
294 if (!parentLayer) return;
295
296 KisImageSP image = parentLayer->image();
297
298 if (!image) {
299 return;
300 }
301
307 if (image->locked()) {
308 m_d->updateSignalCompressor.start();
309 return;
310 }
311
312
313 const QRect extraUpdateRect = m_d->forcedStaticUpdateExtraUpdateRect.takeRect();
314 image->addSpontaneousJob(new KisRecalculateTransformMaskJob(this, extraUpdateRect));
315}
316
318{
326 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
327 KIS_ASSERT_RECOVER(parentLayer) { return new KisPaintDevice(colorSpace()); }
328
329 KisPaintDeviceSP device =
330 new KisPaintDevice(parentLayer->original()->colorSpace());
331 device->setDefaultBounds(parentLayer->original()->defaultBounds());
332
333 QRect requestedRect = parentLayer->original()->exactBounds();
334 parentLayer->buildProjectionUpToNode(device, this, requestedRect);
335
336 return device;
337}
338
340{
348 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
349 KIS_ASSERT_RECOVER(parentLayer) { return new KisPaintDevice(colorSpace()); }
350
351 KisPaintDeviceSP device =
352 new KisPaintDevice(parentLayer->original()->colorSpace());
353 device->setDefaultBounds(parentLayer->original()->defaultBounds());
354
355 QRect requestedRect = parentLayer->original()->exactBounds();
356
358 if (prevSibling) {
359 parentLayer->buildProjectionUpToNode(device, prevSibling, requestedRect);
360 } else {
361 requestedRect = parentLayer->outgoingChangeRect(requestedRect);
362 parentLayer->copyOriginalToProjection(parentLayer->original(), device, requestedRect);
363 }
364
365 return device;
366}
367
369{
370 // TODO: make sure the device is allocated
371 m_d->staticCache.overrideStaticCacheDevice(device);
372}
373
375{
376 return m_d->staticCache.isCacheValid(m_d->paramsHolder->bakeIntoParams());
377}
378
380{
381 if (m_d->testingInterface) {
382 m_d->testingInterface->notifyRecalculateStaticImage();
383 }
384
391 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
393
394 // It might happen that the mask became invisible in the meantime
395 // and the projection has become disabled. That mush be "impossible"
396 // situation, hence assert.
397 KIS_SAFE_ASSERT_RECOVER_RETURN(parentLayer->projection() != parentLayer->paintDevice());
398
399 m_d->staticCache.lazyAllocateStaticCache(parentLayer->original()->colorSpace(),
400 parentLayer->original()->defaultBounds());
401
402 m_d->recalculatingStaticImage = true;
412 QRect requestedRect =
413 parentLayer->changeRect(parentLayer->exactBounds());
414
415 const QRect bounds = parentLayer->original()->defaultBounds()->bounds();
416 const QRect limitingRect = KisAlgebra2D::blowRect(bounds, m_d->offBoundsReadArea);
417
418 requestedRect &= limitingRect;
419
420 // force reset parent layer's projection, because we might have changed
421 // our mask parameters and going to write to some other area
422 parentLayer->projection()->clear();
423
429 parentLayer->updateProjection(requestedRect, this, KisRenderPassFlag::NoTransformMaskUpdates);
430 m_d->recalculatingStaticImage = false;
431}
432
434 KisPaintDeviceSP &dst,
435 const QRect & rc,
436 PositionToFilthy maskPos,
437 KisRenderPassFlags flags) const
438{
439 Q_ASSERT_X(src != dst, "KisTransformMask::decorateRect",
440 "src must be != dst, because we can't create transactions "
441 "during merge, as it breaks reentrancy");
442
443 KisTransformMaskParamsInterfaceSP params = m_d->paramsHolder->bakeIntoParams();
444
445 if (params->isHidden()) return rc;
447 maskPos == N_ABOVE_FILTHY ||
448 maskPos == N_BELOW_FILTHY);
449
456 if (m_d->paramsHolder->defaultBounds()->externalFrameActive()) {
457
458 // no preview for non-affine transforms currently...
459 if (params->isAffine()) {
460 m_d->worker.setForceSubPixelTranslation(m_d->paramsHolder->isAnimated());
461 m_d->worker.setForwardTransform(params->finalAffineTransform());
462 m_d->worker.runPartialDst(src, dst, rc);
463
464#ifdef DEBUG_RENDERING
465 qDebug() << "Partial for external frame" << name() << ppVar(src->exactBounds()) << ppVar(src->extent()) << ppVar(dst->exactBounds()) << ppVar(dst->extent()) << ppVar(rc);
466 KIS_DUMP_DEVICE_2(src, DUMP_RECT, "partial_ext_src", "dd");
467 KIS_DUMP_DEVICE_2(dst, DUMP_RECT, "partial_ext_dst", "dd");
468#endif /* DEBUG_RENDERING */
469 }
470
471 return rc;
472 }
473
474 if (!m_d->staticCache.isCacheOverridden() &&
475 !m_d->recalculatingStaticImage &&
476 (maskPos == N_FILTHY || maskPos == N_ABOVE_FILTHY ||
477 !m_d->staticCache.isCacheValid(params)) &&
478
483
484 if (m_d->testingInterface) {
485 m_d->testingInterface->notifyDecorateRectTriggeredStaticImageUpdate();
486 }
487
488 m_d->staticCache.invalidateDeviceCache();
489 m_d->updateSignalCompressor.start();
490 }
491
492 if (m_d->recalculatingStaticImage) {
493 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->staticCache.isCacheValid(params));
494
495 KisPaintDeviceSP staticCacheDevice = m_d->staticCache.device();
496
497 staticCacheDevice->clear();
498 params->transformDevice(const_cast<KisTransformMask*>(this), src,
499 staticCacheDevice, m_d->paramsHolder->isAnimated());
500 QRect updatedRect = staticCacheDevice->extent();
501 KisPainter::copyAreaOptimized(updatedRect.topLeft(), staticCacheDevice, dst, updatedRect);
502
503 m_d->staticCache.setDeviceCacheValid(params);
504
505#ifdef DEBUG_RENDERING
506 qDebug() << "Recalculate" << name() << ppVar(src->exactBounds()) << ppVar(dst->exactBounds()) << ppVar(rc);
507 KIS_DUMP_DEVICE_2(src, DUMP_RECT, "recalc_src", "dd");
508 KIS_DUMP_DEVICE_2(dst, DUMP_RECT, "recalc_dst", "dd");
509#endif /* DEBUG_RENDERING */
510
511 // Note: overridden cache is **always** valid
512 } else if (params->isAffine() && !m_d->staticCache.isCacheValid(params)) {
513 m_d->worker.setForceSubPixelTranslation(m_d->paramsHolder->isAnimated());
514 m_d->worker.setForwardTransform(params->finalAffineTransform());
515 m_d->worker.runPartialDst(src, dst, rc);
516
517#ifdef DEBUG_RENDERING
518 qDebug() << "Partial" << name() << ppVar(src->exactBounds()) << ppVar(src->extent()) << ppVar(dst->exactBounds()) << ppVar(dst->extent()) << ppVar(rc);
519 KIS_DUMP_DEVICE_2(src, DUMP_RECT, "partial_src", "dd");
520 KIS_DUMP_DEVICE_2(dst, DUMP_RECT, "partial_dst", "dd");
521#endif /* DEBUG_RENDERING */
522
523 } else if (m_d->staticCache.isCacheValid(params)) {
524 KisPainter::copyAreaOptimized(rc.topLeft(), m_d->staticCache.device(), dst, rc);
525
526#ifdef DEBUG_RENDERING
527 qDebug() << "Fetch" << name() << ppVar(src->exactBounds()) << ppVar(dst->exactBounds()) << ppVar(rc);
528 KIS_DUMP_DEVICE_2(src, DUMP_RECT, "fetch_src", "dd");
529 KIS_DUMP_DEVICE_2(dst, DUMP_RECT, "fetch_dst", "dd");
530#endif /* DEBUG_RENDERING */
531
532 }
533
535 this->busyProgressIndicator()->update();
536
537 return rc;
538}
539
541{
542 return v.visit(this);
543}
544
546{
547 return visitor.visit(this, undoAdapter);
548}
549
550namespace {
551QRect calculateInterestRect(KisNodeSP node) {
552 QRect resultInterestRect;
553
554 if (KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data())) {
555 resultInterestRect = group->calculateChildrenLooseUserVisibleBounds();
556 } else {
557 resultInterestRect = node->original()->extent();
558 }
559
560 return resultInterestRect;
561}
562}
563
565{
566 Q_UNUSED(pos);
567
572 if (rect.isEmpty()) return rect;
573
574 KisTransformMaskParamsInterfaceSP params = m_d->paramsHolder->bakeIntoParams();
575
576 QRect changeRect = rect;
577
578 if (params->isAffine()) {
579 QRect bounds;
580 QRect interestRect;
581 KisNodeSP parentNode = parent();
582
583 if (parentNode) {
584 bounds = parentNode->original()->defaultBounds()->bounds();
585 interestRect = calculateInterestRect(parentNode);
586 } else {
587 bounds = QRect(0,0,777,777);
588 interestRect = QRect(0,0,888,888);
589 warnKrita << "WARNING: transform mask has no parent (change rect)."
590 << "Cannot run safe transformations."
591 << "Will limit bounds to" << ppVar(bounds);
592 }
593
594 const QRect limitingRect = KisAlgebra2D::blowRect(bounds, m_d->offBoundsReadArea);
595
596 KisSafeTransform transform(params->finalAffineTransform(), limitingRect, interestRect);
597 changeRect = transform.mapRectForward(rect);
598 } else {
599 changeRect = params->nonAffineChangeRect(rect);
600 }
601
602 return changeRect;
603}
604
606{
607 Q_UNUSED(pos);
608
613 if (rect.isEmpty()) return rect;
614
615 KisTransformMaskParamsInterfaceSP params = m_d->paramsHolder->bakeIntoParams();
616
617 QRect bounds;
618 QRect interestRect;
619 KisNodeSP parentNode = parent();
620
621 if (parentNode) {
622 bounds = parentNode->original()->defaultBounds()->bounds();
623 interestRect = calculateInterestRect(parentNode);
624 } else {
625 bounds = QRect(0,0,777,777);
626 interestRect = QRect(0,0,888,888);
627 warnKrita << "WARNING: transform mask has no parent (need rect)."
628 << "Cannot run safe transformations."
629 << "Will limit bounds to" << ppVar(bounds);
630 }
631
632 QRect needRect = rect;
633
634 if (params->isAffine()) {
635 const QRect limitingRect = KisAlgebra2D::blowRect(bounds, m_d->offBoundsReadArea);
636
637 KisSafeTransform transform(params->finalAffineTransform(), limitingRect, interestRect);
638 needRect = transform.mapRectBackward(rect);
639
646
647 } else {
648 needRect = params->nonAffineNeedRect(rect, interestRect);
649 }
650
651 return needRect;
652}
653
655{
656 QRect rc = KisMask::extent();
657
658 QRect partialChangeRect;
659 QRect existentProjection;
660 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
661 if (parentLayer) {
662 partialChangeRect = parentLayer->partialChangeRect(const_cast<KisTransformMask*>(this), rc);
663 existentProjection = parentLayer->projection()->extent();
664 }
665
666 return changeRect(partialChangeRect) | existentProjection;
667}
668
670{
671 QRect existentProjection;
672 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
673 if (parentLayer) {
674 existentProjection = parentLayer->projection()->exactBounds();
675
676 /* Take into account multiple keyframes... */
677 if (parentLayer->original() && parentLayer->original()->defaultBounds() && parentLayer->original()->keyframeChannel()) {
678 Q_FOREACH( const int& time, parentLayer->original()->keyframeChannel()->allKeyframeTimes() ) {
679 KisRasterKeyframeSP keyframe = parentLayer->original()->keyframeChannel()->keyframeAt<KisRasterKeyframe>(time);
680 existentProjection |= keyframe->contentBounds();
681 }
682 }
683 }
684
685 if (isAnimated()) {
686 existentProjection |= changeRect(image()->bounds());
687 }
688
689 return changeRect(sourceDataBounds()) | existentProjection;
690}
691
693{
697
698 QRect partialChangeRect;
699 KisLayerSP parentLayer = qobject_cast<KisLayer*>(parent().data());
700 if (parentLayer) {
701 const QRect rc = parentLayer->original()->exactBounds();
702 partialChangeRect = parentLayer->partialChangeRect(const_cast<KisTransformMask*>(this), rc);
703 }
704
705 return partialChangeRect;
706}
707
709{
710 m_d->paramsHolder->setDefaultBounds(new KisDefaultBounds(image));
711 m_d->offset.setDefaultBounds(new KisDefaultBounds(image));
713}
714
716{
717 return m_d->offset->x();
718}
719
721{
722 return m_d->offset->y();
723}
724
726{
727 KisTransformMaskParamsInterfaceSP params(m_d->paramsHolder->bakeIntoParams());
728
729 params->translateSrcAndDst(QPointF(x - this->x(), 0));
730
731 setTransformParams(params);
732 m_d->offset->setX(x);
733}
734
736{
737 KisTransformMaskParamsInterfaceSP params(m_d->paramsHolder->bakeIntoParams());
738
739 params->translateSrcAndDst(QPointF(0, y - this->y()));
740
741 setTransformParams(params);
742 m_d->offset->setY(y);
743}
744
746{
747 if (m_d->testingInterface) {
748 m_d->testingInterface->notifyForceUpdateTimedNode();
749 }
750
756 !m_d->staticCache.isCacheValid(m_d->paramsHolder->bakeIntoParams())) {
757
759 }
760}
761
763{
764 return m_d->updateSignalCompressor.isActive();
765}
766
771
773{
774 if (m_d->testingInterface) {
775 m_d->testingInterface->notifyThreadSafeForceStaticImageUpdate();
776 }
777 if (!extraUpdateRect.isEmpty()) {
778 m_d->forcedStaticUpdateExtraUpdateRect.addRect(extraUpdateRect);
779 }
781}
782
787
789{
790 m_d->offset.syncLodCache();
791 m_d->paramsHolder->syncLodCache();
793}
794
796{
797 KisPaintDeviceList devices;
799 if (m_d->staticCache.device()) {
800 devices << m_d->staticCache.device();
801 }
802 return devices;
803}
804
806{
807 m_d->testingInterface.reset(interface);
808}
809
811{
812 return m_d->testingInterface.data();
813}
814
816{
817 if (id == KisKeyframeChannel::PositionX.id() ||
819 id == KisKeyframeChannel::ScaleX.id() ||
820 id == KisKeyframeChannel::ScaleY.id() ||
821 id == KisKeyframeChannel::ShearX.id() ||
822 id == KisKeyframeChannel::ShearY.id() ||
826
827 KisKeyframeChannel *channel = m_d->paramsHolder->requestKeyframeChannel(id);
829 return channel;
830 }
831
833}
834
836{
837 if (id == KisKeyframeChannel::PositionX.id() ||
839 id == KisKeyframeChannel::ScaleX.id() ||
840 id == KisKeyframeChannel::ScaleY.id() ||
841 id == KisKeyframeChannel::ShearX.id() ||
842 id == KisKeyframeChannel::ShearY.id() ||
846 return true;
847 }
848 else if (id == KisKeyframeChannel::Opacity.id()) {
849 return false;
850 }
851
853}
854
qreal v
PythonPluginManager * instance
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
virtual void redo()
virtual QRect bounds() const =0
qreal transformMaskOffBoundsReadArea() const
bool locked() const
Definition kis_image.cc:751
void addSpontaneousJob(KisSpontaneousJob *spontaneousJob)
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
static const KoID RotationY
static const KoID ScaleY
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
static const KoID RotationZ
static const KoID Opacity
static const KoID ScaleX
static const KoID RotationX
static const KoID PositionX
static const KoID PositionY
static const KoID ShearX
static const KoID ShearY
KisRasterKeyframeChannel * keyframeChannel() const
virtual void clear()
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
QRect exactBounds() const
QRect extent() const
const KoColorSpace * colorSpace() const
KisDefaultBoundsBaseSP defaultBounds() const
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
virtual void visit(KisNode *node, KisUndoAdapter *undoAdapter)=0
The KisRasterKeyframe class is a concrete subclass of KisKeyframe that wraps a physical raster image ...
QString id() const
Definition KoID.cpp:63
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
#define bounds(x, a, b)
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
#define UPDATE_DELAY
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
#define KIS_DUMP_DEVICE_2(device, rc, suffix, prefix)
Rect blowRect(const Rect &rect, qreal coeff)
QIcon loadIcon(const QString &name)
void setSupportsLodMoves(bool value)
virtual void setImage(KisImageWSP image)
virtual KisKeyframeChannel * requestKeyframeChannel(const QString &id)
virtual KisPaintDeviceSP original() const =0
KisImageWSP image
bool isAnimated() const
virtual KisPaintDeviceSP paintDevice() const =0
QString name() const
virtual bool supportsKeyframeChannel(const QString &id)
KisPaintDeviceSP projection() const override
Definition kis_layer.cc:820
virtual QRect outgoingChangeRect(const QRect &rect) const
Definition kis_layer.cc:908
QRect exactBounds() const override
QRect updateProjection(const QRect &rect, KisNodeSP filthyNode, KisRenderPassFlags flags)
Definition kis_layer.cc:747
void buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect &rect)
Definition kis_layer.cc:782
QRect partialChangeRect(KisNodeSP lastNode, const QRect &rect)
Definition kis_layer.cc:769
QRect changeRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
Definition kis_layer.cc:859
KisPaintDeviceSP original() const override=0
virtual void copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect &rect) const
Definition kis_layer.cc:801
const KoColorSpace * colorSpace() const override
Definition kis_mask.cc:135
QRect extent() const override
Definition kis_mask.cc:391
KisNodeSP prevSibling() const
Definition kis_node.cpp:402
virtual KisPaintDeviceList getLodCapableDevices() const
Definition kis_node.cpp:682
KisBusyProgressIndicator * busyProgressIndicator
Definition kis_node.cpp:90
PositionToFilthy
Definition kis_node.h:58
@ N_ABOVE_FILTHY
Definition kis_node.h:59
@ N_FILTHY
Definition kis_node.h:61
@ N_BELOW_FILTHY
Definition kis_node.h:62
virtual void syncLodCache()
Definition kis_node.cpp:677
void addKeyframeChannel(KisKeyframeChannel *channel) override
Definition kis_node.cpp:351
KisNodeWSP parent
Definition kis_node.cpp:86
QRectF mapRectForward(const QRectF &rc)
QRectF mapRectBackward(const QRectF &rc)
void setTestingInterface(KisTransformMaskTestingInterface *interface)
KisAnimatedTransformParamsHolderInterfaceSP paramsHolder
void setTransformParamsWithUndo(KisTransformMaskParamsInterfaceSP params, KUndo2Command *parentCommand)
QRect extent() const override
void setY(qint32 y) override
StaticCacheStorage staticCache
AccumulatedRectStorage forcedStaticUpdateExtraUpdateRect
qint32 x() const override
KisPaintDeviceSP buildSourcePreviewDevice()
void forceUpdateTimedNode() override
forceUpdateTimedNode forces the node to regenerate its project. The update might be asynchronous,...
bool supportsKeyframeChannel(const QString &id) override
KisPerspectiveTransformWorker worker
void setX(qint32 x) override
QRect decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect &rc, PositionToFilthy maskPos, KisRenderPassFlags flags) const override
bool accept(KisNodeVisitor &v) override
QRect exactBounds() const override
void syncLodCache() override
qint32 y() const override
KisPaintDeviceSP buildPreviewDevice()
void setImage(KisImageWSP image) override
KisTransformMaskParamsInterfaceSP transformParams() const
KisPaintDeviceList getLodCapableDevices() const override
Private(const Private &rhs)
KisLodCapableLayerOffset offset
Private(KisImageSP image)
QRect changeRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
bool staticImageCacheIsValid() const
bool hasPendingTimedUpdates() const override
KisPaintDeviceSP paintDevice() const override
KisKeyframeChannel * requestKeyframeChannel(const QString &id) override
void overrideStaticCacheDevice(KisPaintDeviceSP device)
QRect needRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
void sigInternalForceStaticImageUpdate()
KisTransformMask(KisImageWSP image, const QString &name)
void setTransformParams(KisTransformMaskParamsInterfaceSP params)
QIcon icon() const override
QRect sourceDataBounds() const
void slotInternalForceStaticImageUpdate()
QScopedPointer< KisTransformMaskTestingInterface > testingInterface
const QScopedPointer< Private > m_d
KisThreadSafeSignalCompressor updateSignalCompressor