Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_mask.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2009 Dmitry Kazakov <dimula73@gmail.com>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_mask.h"
9
10
11#include <kis_debug.h>
12
13// to prevent incomplete class types on "delete selection->flatten();"
14#include <kundo2command.h>
15
16#include <QScopedPointer>
17
18#include <KoColor.h>
19#include <KoColorSpace.h>
21
22#include "kis_paint_device.h"
23#include "kis_selection.h"
24#include "kis_pixel_selection.h"
25#include "kis_painter.h"
26
27#include "kis_image.h"
28#include "kis_layer.h"
29
32
35
36
63
64KisMask::KisMask(KisImageWSP image, const QString &name)
65 : KisNode(image)
66 , m_d(new Private(this))
67{
69 m_d->safeProjection = new KisSafeSelectionNodeProjectionStore();
70 m_d->safeProjection->setImage(image);
71}
72
74 : KisNode(rhs)
76 , m_d(new Private(this))
77{
78 setName(rhs.name());
79
80 m_d->safeProjection = new KisSafeSelectionNodeProjectionStore(*rhs.m_d->safeProjection);
81
82 if (rhs.m_d->selection) {
83 m_d->selection = new KisSelection(*rhs.m_d->selection.data());
84 m_d->selection->setParentNode(this);
85
86 KisPixelSelectionSP pixelSelection = m_d->selection->pixelSelection();
87 if (pixelSelection->framesInterface()) {
88 addKeyframeChannel(pixelSelection->keyframeChannel());
90 }
91 }
92}
93
95{
96 if (m_d->selection) {
97 m_d->selection->setParentNode(0);
98 }
99
100 delete m_d;
101}
102
104{
105 KisPaintDeviceSP parentPaintDevice = parent() ? parent()->original() : 0;
106 KisDefaultBoundsBaseSP defaultBounds;
107
108 if (parentPaintDevice) {
109 defaultBounds = new KisSelectionDefaultBounds(parentPaintDevice);
110 } else {
111 if (image) {
112 qWarning() << "WARNING: KisMask::setImage() was called without any parent layer being set";
113 }
114
115 // just a fallback solution
116 defaultBounds = new KisDefaultBounds(image);
117 }
118
119 if (m_d->selection) {
120 m_d->selection->setDefaultBounds(defaultBounds);
121 m_d->selection->setResolutionProxy(m_d->selection->resolutionProxy()->createOrCloneDetached(image));
122 }
123
124 m_d->safeProjection->setImage(image);
125
127}
128
130{
131 Q_UNUSED(node);
132 return false;
133}
134
136{
137 KisNodeSP parentNode = parent();
138 return parentNode ? parentNode->colorSpace() : 0;
139}
140
142{
150 const KoColorSpace *colorSpace = this->colorSpace();
151 if (!colorSpace) return 0;
152
154 return op ? op : colorSpace->compositeOp(COMPOSITE_OVER);
155}
156
158{
159 m_d->initSelectionImpl(copyFrom, parentLayer, 0, image());
160}
161
162void KisMask::initSelection(KisPaintDeviceSP copyFromDevice, KisLayerSP parentLayer)
163{
164 m_d->initSelectionImpl(0, parentLayer, copyFromDevice, image());
165}
166
168{
169 m_d->initSelectionImpl(0, parentLayer, 0, image());
170}
171
172void KisMask::Private::initSelectionImpl(KisSelectionSP copyFrom, KisLayerSP parentLayer, KisPaintDeviceSP copyFromDevice, KisImageWSP image)
173{
174 Q_ASSERT(parentLayer);
175
176 KisPaintDeviceSP parentPaintDevice = parentLayer->original();
177
178 if (copyFrom) {
182 selection = new KisSelection(*copyFrom);
183 selection->setDefaultBounds(new KisSelectionDefaultBounds(parentPaintDevice));
184 selection->setResolutionProxy(copyFrom->resolutionProxy()->createOrCloneDetached(image));
185 } else if (copyFromDevice) {
187 q->inherits("KisFilterMask") || q->inherits("KisTransparencyMask") ?
189
190 selection = new KisSelection(copyFromDevice, copyMode,
191 new KisSelectionDefaultBounds(parentPaintDevice),
193
194 KisPixelSelectionSP pixelSelection = selection->pixelSelection();
195 if (pixelSelection->framesInterface()) {
196 KisRasterKeyframeChannel *keyframeChannel = pixelSelection->keyframeChannel();
197 keyframeChannel->setFilenameSuffix(".pixelselection");
198
199 q->addKeyframeChannel(keyframeChannel);
200 q->enableAnimation();
201 }
202 } else {
203 selection = new KisSelection(new KisSelectionDefaultBounds(parentPaintDevice),
205 selection->pixelSelection()->setDefaultPixel(KoColor(Qt::white, selection->pixelSelection()->colorSpace()));
206
207 if (deferredSelectionOffset) {
208 selection->setX(deferredSelectionOffset->x());
209 selection->setY(deferredSelectionOffset->y());
210 deferredSelectionOffset.reset();
211 }
212 }
213 selection->setParentNode(q);
214 selection->pixelSelection()->setSupportsWraparoundMode(true);
215 selection->updateProjection();
216}
217
219{
220 return m_d->selection;
221}
222
224{
226 return selection ? selection->pixelSelection() : 0;
227}
228
230{
231 return paintDevice();
232}
233
235{
236 KisPaintDeviceSP originalDevice = original();
237 KisPaintDeviceSP result = originalDevice;
238
240 if (selection && hasTemporaryTarget()) {
241 result = m_d->safeProjection->getDeviceLazy(selection)->pixelSelection();
242 }
243
244 return result;
245}
246
248{
249 return m_d->projectionPlane;
250}
251
253{
254 m_d->selection = selection;
255 m_d->selection->setDefaultBounds(new KisDefaultBounds(image()));
256 m_d->selection->setResolutionProxy(toQShared(new KisImageResolutionProxy(image())));
257 m_d->selection->setParentNode(this);
258 m_d->selection->pixelSelection()->setSupportsWraparoundMode(true);
259}
260
261void KisMask::select(const QRect & rc, quint8 selectedness)
262{
265 psel->select(rc, selectedness);
266 sel->updateProjection(rc);
267}
268
269
271 KisPaintDeviceSP &dst,
272 const QRect & rc,
273 PositionToFilthy maskPos,
274 KisRenderPassFlags flags) const
275{
276 Q_UNUSED(src);
277 Q_UNUSED(dst);
278 Q_UNUSED(maskPos);
279 Q_UNUSED(flags);
280 Q_ASSERT_X(0, "KisMask::decorateRect", "Should be overridden by successors");
281 return rc;
282}
283
285{
286 return false;
287}
288
289void KisMask::apply(KisPaintDeviceSP projection, const QRect &applyRect, const QRect &needRect, PositionToFilthy maskPos, KisRenderPassFlags flags) const
290{
291 if (selection()) {
292
293 flattenSelectionProjection(m_d->selection, applyRect);
294
295 KisSelectionSP effectiveSelection = m_d->selection;
296
297 {
298 // Access temporary target under the lock held
300
301 if (!paintsOutsideSelection()) {
302 // extent of m_d->selection should also be accessed under a lock,
303 // because it might be being merged in by the temporary target atm
304 QRect effectiveExtent = m_d->selection->selectedRect();
305
306 if (hasTemporaryTarget()) {
307 effectiveExtent |= temporaryTarget()->extent();
308 }
309
310 if(!effectiveExtent.intersects(applyRect)) {
311 return;
312 }
313 }
314
315 if (hasTemporaryTarget()) {
316 effectiveSelection = m_d->safeProjection->getDeviceLazy(m_d->selection);
317
318 KisPainter::copyAreaOptimized(applyRect.topLeft(),
319 m_d->selection->pixelSelection(),
320 effectiveSelection->pixelSelection(), applyRect);
321
322 KisPainter gc(effectiveSelection->pixelSelection());
324 gc.bitBlt(applyRect.topLeft(), temporaryTarget(), applyRect);
325 } else {
326 m_d->safeProjection->releaseDevice();
327 }
328
329 mergeInMaskInternal(projection, effectiveSelection, applyRect, needRect, maskPos, flags);
330 }
331
332 } else {
333 mergeInMaskInternal(projection, 0, applyRect, needRect, maskPos, flags);
334 }
335}
336
338 KisSelectionSP effectiveSelection,
339 const QRect &applyRect,
340 const QRect &preparedNeedRect,
342 KisRenderPassFlags flags) const
343{
344 KisCachedPaintDevice::Guard d1(projection, m_d->paintDeviceCache);
345 KisPaintDeviceSP cacheDevice = d1.device();
346
347 if (effectiveSelection) {
348 QRect updatedRect = decorateRect(projection, cacheDevice, applyRect, maskPos, flags);
349
350 // masks don't have any compositing
351 KisPainter::copyAreaOptimized(updatedRect.topLeft(), cacheDevice, projection, updatedRect, effectiveSelection);
352
353 } else {
354 cacheDevice->makeCloneFromRough(projection, preparedNeedRect);
355 projection->clear(preparedNeedRect);
356
357 decorateRect(cacheDevice, projection, applyRect, maskPos, flags);
358 }
359}
360
361void KisMask::flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const
362{
363 selection->updateProjection(dirtyRect);
364}
365
366QRect KisMask::needRect(const QRect &rect, PositionToFilthy pos) const
367{
368 Q_UNUSED(pos);
369 QRect resultRect = rect;
370 if (m_d->selection) {
371 QRect selectionExtent = m_d->selection->selectedRect();
372
373 // copy for thread safety!
375
376 if (temporaryTarget) {
377 selectionExtent |= temporaryTarget->extent();
378 }
379
380 resultRect &= selectionExtent;
381 }
382
383 return resultRect;
384}
385
386QRect KisMask::changeRect(const QRect &rect, PositionToFilthy pos) const
387{
388 return KisMask::needRect(rect, pos);
389}
390
391QRect KisMask::extent() const
392{
393 QRect resultRect;
394
395 if (m_d->selection) {
396 resultRect = m_d->selection->selectedRect();
397
398 // copy for thread safety!
400
401 if (temporaryTarget) {
402 resultRect |= temporaryTarget->extent();
403 }
404 } else if (KisNodeSP parent = this->parent()) {
405 resultRect = parent->extent();
406 }
407
408 return resultRect;
409}
410
412{
413 QRect resultRect;
414
415 if (m_d->selection) {
416 resultRect = m_d->selection->selectedExactRect();
417
418 // copy for thread safety!
420
421 if (temporaryTarget) {
422 resultRect |= temporaryTarget->exactBounds();
423 }
424 } else if (KisNodeSP parent = this->parent()) {
425 resultRect = parent->exactBounds();
426 }
427
428 return resultRect;
429}
430
431qint32 KisMask::x() const
432{
433 return m_d->selection ? m_d->selection->x() :
434 m_d->deferredSelectionOffset ? m_d->deferredSelectionOffset->x() :
435 parent() ? parent()->x() : 0;
436}
437
438qint32 KisMask::y() const
439{
440 return m_d->selection ? m_d->selection->y() :
441 m_d->deferredSelectionOffset ? m_d->deferredSelectionOffset->y() :
442 parent() ? parent()->y() : 0;
443}
444
445void KisMask::setX(qint32 x)
446{
447 if (m_d->selection) {
448 m_d->selection->setX(x);
449 } else if (!m_d->deferredSelectionOffset) {
450 m_d->deferredSelectionOffset.reset(new QPoint(x, 0));
451 } else {
452 m_d->deferredSelectionOffset->rx() = x;
453 }
454}
455
456void KisMask::setY(qint32 y)
457{
458 if (m_d->selection) {
459 m_d->selection->setY(y);
460 } else if (!m_d->deferredSelectionOffset) {
461 m_d->deferredSelectionOffset.reset(new QPoint(0, y));
462 } else {
463 m_d->deferredSelectionOffset->ry() = y;
464 }
465}
466
468{
469 return QRect();
470}
471
472QImage KisMask::createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode)
473{
474 KisPaintDeviceSP originalDevice =
475 selection() ? selection()->projection() : 0;
476
477 return originalDevice ?
478 originalDevice->createThumbnail(w, h, aspectRatioMode, 1,
481}
482
484{
485 KisPaintDeviceSP originalDevice =
486 selection() ? selection()->projection() : 0;
487 return originalDevice ? originalDevice->sequenceNumber() : -1;
488}
489
490void KisMask::testingInitSelection(const QRect &rect, KisLayerSP parentLayer)
491{
492 if (parentLayer) {
493 m_d->selection = new KisSelection(new KisSelectionDefaultBounds(parentLayer->paintDevice()), toQShared(new KisImageResolutionProxy(image())));
494 } else {
496 }
497
498 m_d->selection->pixelSelection()->select(rect, OPACITY_OPAQUE_U8);
499 m_d->selection->pixelSelection()->setSupportsWraparoundMode(true);
500 m_d->selection->updateProjection(rect);
501 m_d->selection->setParentNode(this);
502}
503
505{
506 return !m_d->selection || !m_d->selection->hasShapeSelection();
507}
508
510{
511 if (id == KisKeyframeChannel::Raster.id()) {
512 KisPaintDeviceSP device = paintDevice();
513 if (device) {
515 contentChannel->setFilenameSuffix(".pixelselection");
516 return contentChannel;
517 }
518 }
519
521}
522
523bool KisMask::supportsKeyframeChannel(const QString &id)
524{
525 if (id == KisKeyframeChannel::Raster.id() && paintDevice()) {
526 return true;
527 }
528
530}
531
533{
534 KisNodeSP up = parent();
535 KisLayer *layer = dynamic_cast<KisLayer*>(up.data());
536 if (layer) {
537 layer->notifyChildMaskChanged();
538 }
540}
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
static const KoID Raster
KisRasterKeyframeChannel * keyframeChannel() const
virtual void clear()
void makeCloneFromRough(KisPaintDeviceSP src, const QRect &minimalRect)
int sequenceNumber() const
QImage createThumbnail(qint32 maxw, qint32 maxh, QRect rect, qreal oversample=1, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags())
KisPaintDeviceFramesInterface * framesInterface()
QRect exactBounds() const
QRect extent() const
KisRasterKeyframeChannel * createKeyframeChannel(const KoID &id)
static void copyAreaOptimized(const QPoint &dstPt, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect &originalSrcRect)
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
void setFilenameSuffix(const QString &suffix)
const KoCompositeOp * compositeOp(const QString &id, const KoColorSpace *srcSpace=nullptr) const
QSharedPointer< T > toQShared(T *ptr)
const QString & compositeOpId() const
virtual qint32 y() const
virtual QRect exactBounds() const
virtual KisKeyframeChannel * requestKeyframeChannel(const QString &id)
virtual KisPaintDeviceSP original() const =0
void setName(const QString &name)
virtual const KoColorSpace * colorSpace() const =0
KisImageWSP image
virtual qint32 x() const
virtual QRect extent() const
virtual KisPaintDeviceSP paintDevice() const =0
QString name() const
void enableAnimation()
virtual bool supportsKeyframeChannel(const QString &id)
KisPaintDeviceSP device() const
void setupTemporaryPainter(KisPainter *painter) const
void notifyChildMaskChanged()
Definition kis_layer.cc:493
KisPaintDeviceSP original() const override=0
KisPaintDeviceSP projection() const override
Definition kis_mask.cc:234
void apply(KisPaintDeviceSP projection, const QRect &applyRect, const QRect &needRect, PositionToFilthy maskPos, KisRenderPassFlags flags) const
Definition kis_mask.cc:289
virtual bool paintsOutsideSelection() const
Definition kis_mask.cc:284
qint32 x() const override
Definition kis_mask.cc:431
KisPaintDeviceSP original() const override
Definition kis_mask.cc:229
KisMask * q
Definition kis_mask.cc:46
virtual QRect nonDependentExtent() const
Definition kis_mask.cc:467
bool supportsLodPainting() const override
Definition kis_mask.cc:504
KisKeyframeChannel * requestKeyframeChannel(const QString &id) override
Definition kis_mask.cc:509
QScopedPointer< QPoint > deferredSelectionOffset
Definition kis_mask.cc:56
virtual void flattenSelectionProjection(KisSelectionSP selection, const QRect &dirtyRect) const
Definition kis_mask.cc:361
bool supportsKeyframeChannel(const QString &id) override
Definition kis_mask.cc:523
void setImage(KisImageWSP image) override
Definition kis_mask.cc:103
QRect needRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
Definition kis_mask.cc:366
Private(KisMask *_q)
Definition kis_mask.cc:38
KisSafeSelectionNodeProjectionStoreSP safeProjection
Definition kis_mask.cc:59
int thumbnailSeqNo() const override
Definition kis_mask.cc:483
KisMask(KisImageWSP image, const QString &name)
Definition kis_mask.cc:64
void initSelectionImpl(KisSelectionSP copyFrom, KisLayerSP parentLayer, KisPaintDeviceSP copyFromDevice, KisImageWSP image)
const KoCompositeOp * compositeOp() const override
Definition kis_mask.cc:141
virtual QRect decorateRect(KisPaintDeviceSP &src, KisPaintDeviceSP &dst, const QRect &rc, PositionToFilthy maskPos, KisRenderPassFlags flags) const
Definition kis_mask.cc:270
QImage createThumbnail(qint32 w, qint32 h, Qt::AspectRatioMode aspectRatioMode=Qt::IgnoreAspectRatio) override
Definition kis_mask.cc:472
qint32 y() const override
Definition kis_mask.cc:438
void setY(qint32 y) override
Definition kis_mask.cc:456
void baseNodeChangedCallback() override
Definition kis_mask.cc:532
Private *const m_d
Definition kis_mask.h:226
KisCachedPaintDevice paintDeviceCache
Definition kis_mask.cc:45
void testingInitSelection(const QRect &rect, KisLayerSP parentLayer)
Definition kis_mask.cc:490
~KisMask() override
Definition kis_mask.cc:94
const KoColorSpace * colorSpace() const override
Definition kis_mask.cc:135
void setX(qint32 x) override
Definition kis_mask.cc:445
virtual void mergeInMaskInternal(KisPaintDeviceSP projection, KisSelectionSP effectiveSelection, const QRect &applyRect, const QRect &preparedNeedRect, PositionToFilthy maskPos, KisRenderPassFlags flags) const
Definition kis_mask.cc:337
QRect changeRect(const QRect &rect, PositionToFilthy pos=N_FILTHY) const override
Definition kis_mask.cc:386
bool allowAsChild(KisNodeSP node) const override
Definition kis_mask.cc:129
QRect exactBounds() const override
Definition kis_mask.cc:411
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
void setSelection(KisSelectionSP selection)
Definition kis_mask.cc:252
KisSelectionSP selection
Definition kis_mask.cc:44
KisAbstractProjectionPlaneSP projectionPlane
Definition kis_mask.cc:58
QRect extent() const override
Definition kis_mask.cc:391
void select(const QRect &rc, quint8 selectedness=MAX_SELECTED)
Definition kis_mask.cc:261
KisPaintDeviceSP paintDevice() const override
Definition kis_mask.cc:223
void baseNodeChangedCallback() override
Definition kis_node.cpp:329
void setImage(KisImageWSP newImage) override
Definition kis_node.cpp:254
PositionToFilthy
Definition kis_node.h:58
void addKeyframeChannel(KisKeyframeChannel *channel) override
Definition kis_node.cpp:351
KisNodeWSP parent
Definition kis_node.cpp:86
void select(const QRect &r, quint8 selectedness=MAX_SELECTED)
KisPixelSelectionSP projection() const
void updateProjection(const QRect &rect)
KisImageResolutionProxySP resolutionProxy
KisPixelSelectionSP pixelSelection