43#include <QReadWriteLock>
52class StaticCacheStorage
56 QReadLocker l(&m_lock);
59 paramsForStaticImage ||
60 staticCacheIsOverridden);
62 return staticCacheValid &&
63 (!paramsForStaticImage ||
64 paramsForStaticImage->compareTransform(currentParams));
67 bool isCacheOverridden()
const {
68 QReadLocker l(&m_lock);
72 return staticCacheIsOverridden;
76 QWriteLocker l(&m_lock);
78 if (!staticCacheDevice ||
79 *staticCacheDevice->colorSpace() != *cs) {
82 staticCacheDevice->setDefaultBounds(defaultBounds);
87 return staticCacheDevice;
91 QWriteLocker l(&m_lock);
93 paramsForStaticImage = currentParams;
94 staticCacheValid =
true;
102 staticCacheDevice->clear();
105 const QRect rc = device->
extent();
110 QWriteLocker l(&m_lock);
111 paramsForStaticImage.clear();
112 staticCacheValid = bool(device);
113 staticCacheIsOverridden = bool(device);
117 void invalidateDeviceCache() {
118 staticCacheValid =
false;
119 paramsForStaticImage.clear();
124 mutable QReadWriteLock m_lock;
125 bool staticCacheIsOverridden {
false};
126 bool staticCacheValid = {
false};
131struct AccumulatedRectStorage
133 void addRect(
const QRect &rc) {
134 QMutexLocker l(&m_mutex);
139 QMutexLocker l(&m_mutex);
141 const QRect
rect = m_rect;
154#define UPDATE_DELAY 3000
159 : worker(0, QTransform(), true, 0),
161 recalculatingStaticImage(false),
164 offBoundsReadArea(0.5)
169 : worker(rhs.worker),
170 paramsHolder(rhs.paramsHolder->clone()),
171 recalculatingStaticImage(rhs.recalculatingStaticImage),
174 offBoundsReadArea(rhs.offBoundsReadArea)
230 Q_FOREACH (
const QString &
id, ids) {
252 m_d->paramsHolder->setParamsAtCurrentPosition(params.data(), parentCommand);
261 m_d->staticCache.invalidateDeviceCache();
262 m_d->updateSignalCompressor.start();
267 return m_d->paramsHolder->bakeIntoParams();
272 if (
m_d->testingInterface) {
273 m_d->testingInterface->notifySlotDelayedStaticUpdate();
281 m_d->staticCache.invalidateDeviceCache();
282 m_d->updateSignalCompressor.stop();
294 if (!parentLayer)
return;
308 m_d->updateSignalCompressor.start();
313 const QRect extraUpdateRect =
m_d->forcedStaticUpdateExtraUpdateRect.takeRect();
371 m_d->staticCache.overrideStaticCacheDevice(device);
376 return m_d->staticCache.isCacheValid(
m_d->paramsHolder->bakeIntoParams());
381 if (
m_d->testingInterface) {
382 m_d->testingInterface->notifyRecalculateStaticImage();
402 m_d->recalculatingStaticImage =
true;
412 QRect requestedRect =
418 requestedRect &= limitingRect;
430 m_d->recalculatingStaticImage =
false;
437 KisRenderPassFlags flags)
const
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");
445 if (params->isHidden())
return rc;
456 if (
m_d->paramsHolder->defaultBounds()->externalFrameActive()) {
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);
464#ifdef DEBUG_RENDERING
474 if (!
m_d->staticCache.isCacheOverridden() &&
475 !
m_d->recalculatingStaticImage &&
477 !
m_d->staticCache.isCacheValid(params)) &&
484 if (
m_d->testingInterface) {
485 m_d->testingInterface->notifyDecorateRectTriggeredStaticImageUpdate();
488 m_d->staticCache.invalidateDeviceCache();
489 m_d->updateSignalCompressor.start();
492 if (
m_d->recalculatingStaticImage) {
497 staticCacheDevice->
clear();
499 staticCacheDevice,
m_d->paramsHolder->isAnimated());
500 QRect updatedRect = staticCacheDevice->
extent();
503 m_d->staticCache.setDeviceCacheValid(params);
505#ifdef DEBUG_RENDERING
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);
517#ifdef DEBUG_RENDERING
523 }
else if (
m_d->staticCache.isCacheValid(params)) {
526#ifdef DEBUG_RENDERING
542 return v.visit(
this);
547 return visitor.
visit(
this, undoAdapter);
551QRect calculateInterestRect(
KisNodeSP node) {
552 QRect resultInterestRect;
555 resultInterestRect = group->calculateChildrenLooseUserVisibleBounds();
560 return resultInterestRect;
578 if (params->isAffine()) {
585 interestRect = calculateInterestRect(parentNode);
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."
596 KisSafeTransform transform(params->finalAffineTransform(), limitingRect, interestRect);
623 interestRect = calculateInterestRect(parentNode);
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."
634 if (params->isAffine()) {
637 KisSafeTransform transform(params->finalAffineTransform(), limitingRect, interestRect);
648 needRect = params->nonAffineNeedRect(
rect, interestRect);
658 QRect partialChangeRect;
659 QRect existentProjection;
666 return changeRect(partialChangeRect) | existentProjection;
671 QRect existentProjection;
680 existentProjection |= keyframe->contentBounds();
698 QRect partialChangeRect;
705 return partialChangeRect;
717 return m_d->offset->x();
722 return m_d->offset->y();
729 params->translateSrcAndDst(QPointF(
x - this->
x(), 0));
732 m_d->offset->setX(
x);
739 params->translateSrcAndDst(QPointF(0,
y - this->
y()));
742 m_d->offset->setY(
y);
747 if (
m_d->testingInterface) {
748 m_d->testingInterface->notifyForceUpdateTimedNode();
756 !
m_d->staticCache.isCacheValid(
m_d->paramsHolder->bakeIntoParams())) {
764 return m_d->updateSignalCompressor.isActive();
774 if (
m_d->testingInterface) {
775 m_d->testingInterface->notifyThreadSafeForceStaticImageUpdate();
777 if (!extraUpdateRect.isEmpty()) {
778 m_d->forcedStaticUpdateExtraUpdateRect.addRect(extraUpdateRect);
790 m_d->offset.syncLodCache();
791 m_d->paramsHolder->syncLodCache();
799 if (
m_d->staticCache.device()) {
800 devices <<
m_d->staticCache.device();
807 m_d->testingInterface.reset(interface);
812 return m_d->testingInterface.data();
PythonPluginManager * instance
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
virtual QRect bounds() const =0
qreal transformMaskOffBoundsReadArea() const
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
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 RotationX
static const KoID PositionX
static const KoID PositionY
KisRasterKeyframeChannel * keyframeChannel() const
void setDefaultBounds(KisDefaultBoundsBaseSP bounds)
QRect exactBounds() 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 ...
#define KIS_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_NOOP(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
T kisGrowRect(const T &rect, U offset)
#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
virtual KisPaintDeviceSP paintDevice() const =0
virtual bool supportsKeyframeChannel(const QString &id)
KisPaintDeviceSP projection() const override
virtual QRect outgoingChangeRect(const QRect &rect) const
QRect exactBounds() const override
QRect updateProjection(const QRect &rect, KisNodeSP filthyNode, KisRenderPassFlags flags)
void buildProjectionUpToNode(KisPaintDeviceSP projection, KisNodeSP lastNode, const QRect &rect)
QRect partialChangeRect(KisNodeSP lastNode, const QRect &rect)
QRect changeRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
KisPaintDeviceSP original() const override=0
virtual void copyOriginalToProjection(const KisPaintDeviceSP original, KisPaintDeviceSP projection, const QRect &rect) const
const KoColorSpace * colorSpace() const override
QRect extent() const override
KisNodeSP prevSibling() const
virtual KisPaintDeviceList getLodCapableDevices() const
KisBusyProgressIndicator * busyProgressIndicator
virtual void syncLodCache()
void addKeyframeChannel(KisKeyframeChannel *channel) override