Krita Source Code Documentation
Loading...
Searching...
No Matches
KisLayerUtils Namespace Reference

Namespaces

namespace  Private
 

Classes

struct  ActivateSelectionMask
 
struct  AddNewFrame
 
struct  CleanUpNodes
 
struct  ConvertToPaintLayerInfo
 
struct  CreateMergedLayer
 
struct  CreateMergedLayerMultiple
 
struct  DisableColorizeKeyStrokes
 
struct  DisableExtraCompositing
 
struct  DisableOnionSkins
 
struct  DisablePassThroughForHeadsOnly
 
struct  EphemeralCommandsWrapper
 
struct  FillSelectionMasks
 
struct  InitSplitAlphaSelectionMask
 
struct  InsertNode
 
struct  KeepMergedNodesSelected
 
class  KeepNodesSelectedCommand
 
class  KisSimpleUpdateCommand
 
struct  MergeDownInfo
 
struct  MergeDownInfoBase
 
struct  MergeLayers
 
struct  MergeLayersMultiple
 
struct  MergeMetaData
 
struct  MergeMultipleInfo
 
struct  MergeSelectionMasks
 
struct  RefreshDelayedUpdateLayers
 
struct  RefreshHiddenAreas
 
class  RemoveNodeHelper
 
struct  SelectGlobalSelectionMask
 
struct  SimpleAddNode
 
struct  SimpleRemoveLayers
 
struct  SplitAlphaCommand
 
struct  SplitAlphaToMaskInfo
 
struct  SwitchFrameCommand
 The SwitchFrameCommand struct Switches to frame with undo/redo support. More...
 
struct  UndoEphemeralCommands
 
struct  UploadProjectionToFrameCommand
 

Typedefs

typedef QSharedPointer< ConvertToPaintLayerInfoConvertToPaintLayerInfoSP
 
typedef QMap< int, QSet< KisNodeSP > > FrameJobs
 
typedef QSharedPointer< MergeDownInfoBaseMergeDownInfoBaseSP
 
typedef QSharedPointer< MergeDownInfoMergeDownInfoSP
 
typedef QSharedPointer< MergeMultipleInfoMergeMultipleInfoSP
 
typedef QSharedPointer< SplitAlphaToMaskInfoSplitAlphaToMaskInfoSP
 

Enumerations

enum  MergeFlag { None , SkipMergingFrames = 0x1 }
 

Functions

void addCopyOfNameTag (KisNodeSP node)
 
bool canChangeImageProfileInvisibly (KisImageSP image)
 
void changeImageDefaultProjectionColor (KisImageSP image, const KoColor &color)
 
bool checkIsChildOf (KisNodeSP node, const KisNodeList &parents)
 
bool checkIsCloneOf (KisNodeSP node, const KisNodeList &nodes)
 
template<typename T >
bool checkNodesDiffer (KisNodeList nodes, std::function< T(KisNodeSP)> checkerFunc)
 
std::future< KisNodeSPconvertToPaintLayer (KisImageSP image, KisNodeSP src)
 
int fetchLayerActiveRasterFrameID (KisNodeSP node)
 
KisTimeSpan fetchLayerActiveRasterFrameSpan (KisNodeSP node, const int time)
 
int fetchLayerActiveRasterFrameTime (KisNodeSP node)
 
QSet< int > fetchLayerFrames (KisNodeSP node)
 
QSet< int > fetchLayerFramesRecursive (KisNodeSP rootNode)
 
QSet< int > fetchLayerIdenticalRasterFrameTimes (KisNodeSP node, const int &frameTime)
 
QSet< int > fetchLayerRasterFrameTimesMatchingID (KisNodeSP node, const int frameID)
 
QSet< int > fetchLayerRasterIDsAtTimes (KisNodeSP node, const QSet< int > &times)
 
QSet< int > fetchLayerUniqueRasterTimesMatchingIDs (KisNodeSP node, QSet< int > &frameIDs)
 
void fetchSelectionMasks (KisNodeList mergedNodes, QVector< KisSelectionMaskSP > &selectionMasks)
 
QSet< int > fetchUniqueFrameTimes (KisNodeSP node, QSet< int > selectedTimes, bool filterActiveFrameID)
 
KisNodeList filterInvisibleNodes (const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
 
void filterMergeableNodes (KisNodeList &nodes, bool allowMasks)
 
QSet< int > filterTimesForOnlyRasterKeyedTimes (KisNodeSP node, const QSet< int > &times)
 
void filterUnlockedNodes (KisNodeList &nodes)
 
KisImageSP findImageByHierarchy (KisNodeSP node)
 
KisNodeSP findIsolationRoot (KisNodeSP node)
 
KisNodeSP findNodeByName (KisNodeSP root, const QString &name)
 
template<class T >
T * findNodeByType (KisNodeSP root)
 
KisNodeSP findNodeByUuid (KisNodeSP root, const QUuid &uuid)
 
QList< KisNodeSPfindNodesByName (KisNodeSP root, const QString &name, bool recursive, bool partialMatch)
 
KisNodeList findNodesWithProps (KisNodeSP root, const KoProperties &props, bool excludeRoot)
 
KisNodeSP findRoot (KisNodeSP node)
 
void flattenImage (KisImageSP image, KisNodeSP activeNode, MergeFlags flags)
 
void flattenLayer (KisImageSP image, KisLayerSP layer, MergeFlags flags)
 
void forceAllDelayedNodesUpdate (KisNodeSP root)
 
void forceAllHiddenOriginalsUpdate (KisNodeSP root)
 
bool hasDelayedNodeWithUpdates (KisNodeSP root)
 
void mergeDown (KisImageSP image, KisLayerSP layer, const KisMetaData::MergeStrategy *strategy, MergeFlags flags)
 
void mergeMultipleLayers (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)
 
void mergeMultipleLayersImpl (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, bool flattenSingleLayer, const KUndo2MagicString &actionName, bool cleanupNodes=true, const QString layerName=QString(), MergeFlags flags=None)
 
void mergeMultipleNodes (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)
 
void newLayerFromVisible (KisImageSP image, KisNodeSP putAfter, MergeFlags flags)
 
template<typename NodePointer , typename Functor >
void recursiveApplyNodes (NodePointer node, Functor func)
 
KisNodeSP recursiveFindNode (KisNodeSP node, std::function< bool(KisNodeSP)> func)
 
QRect recursiveTightNodeVisibleBounds (KisNodeSP rootNode)
 
void refreshHiddenAreaAsync (KisImageSP image, KisNodeSP rootNode, const QRect &preparedArea)
 
KisNodeList sortAndFilterAnyMergeableNodesSafe (const KisNodeList &nodes, KisImageSP image)
 
KisNodeList sortAndFilterMergeableInternalNodes (KisNodeList nodes, bool allowMasks)
 
KisNodeList sortMergeableInternalNodes (KisNodeList nodes)
 
void sortMergeableNodes (KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
 
KisNodeList sortMergeableNodes (KisNodeSP root, KisNodeList nodes)
 
KRITAIMAGE_EXPORT void sortMergeableNodes (KisNodeSP root, QList< KisNodeSP > &inputNodes, QList< KisNodeSP > &outputNodes)
 
void splitAlphaToMask (KisImageSP image, KisNodeSP node, const QString &maskName)
 
void splitNonRemovableNodes (KisNodeList &nodesToRemove, KisNodeList &_nodesToHide)
 
bool tryMergeSelectionMasks (KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter)
 
void updateFrameJobs (FrameJobs *jobs, KisNodeSP node)
 
void updateFrameJobsRecursive (FrameJobs *jobs, KisNodeSP rootNode)
 

Typedef Documentation

◆ ConvertToPaintLayerInfoSP

◆ FrameJobs

typedef QMap<int, QSet<KisNodeSP> > KisLayerUtils::FrameJobs

Definition at line 94 of file kis_layer_utils.h.

◆ MergeDownInfoBaseSP

◆ MergeDownInfoSP

◆ MergeMultipleInfoSP

◆ SplitAlphaToMaskInfoSP

Enumeration Type Documentation

◆ MergeFlag

Enumerator
None 
SkipMergingFrames 

Definition at line 31 of file kis_layer_utils.h.

31 {
32 None,
34 };

Function Documentation

◆ addCopyOfNameTag()

KRITAIMAGE_EXPORT void KisLayerUtils::addCopyOfNameTag ( KisNodeSP node)

Definition at line 1709 of file kis_layer_utils.cpp.

1710 {
1711 if (!KisImageConfig(true).renameDuplicatedLayers()) { return; }
1712
1713 const QString prefix = i18n("Copy of");
1714 QString newName = node->name();
1715 if (!newName.startsWith(prefix)) {
1716 newName = QString("%1 %2").arg(prefix).arg(newName);
1717 node->setName(newName);
1718 }
1719 }
void setName(const QString &name)
QString name() const

References KisBaseNode::name(), and KisBaseNode::setName().

◆ canChangeImageProfileInvisibly()

KRITAIMAGE_EXPORT bool KisLayerUtils::canChangeImageProfileInvisibly ( KisImageSP image)

Definition at line 2349 of file kis_layer_utils.cpp.

2350 {
2351 int numLayers = 0;
2352 bool hasNonNormalLayers = false;
2353 bool hasTransparentLayer = false;
2354
2355
2356 recursiveApplyNodes(image->root(),
2357 [&numLayers, &hasNonNormalLayers, &hasTransparentLayer, image] (KisNodeSP node) {
2358 if (!node->inherits("KisLayer")) return;
2359
2360 numLayers++;
2361
2362 if (node->exactBounds().isEmpty()) return;
2363
2364 // this is only an approximation! it is not exact!
2365 if (!hasTransparentLayer &&
2366 node->exactBounds() != image->bounds()) {
2367
2368 hasTransparentLayer = true;
2369 }
2370
2371 if (!hasNonNormalLayers &&
2372 node->compositeOpId() != COMPOSITE_OVER) {
2373
2374 hasNonNormalLayers = true;
2375 }
2376 });
2377
2378 return numLayers == 1 || (!hasNonNormalLayers && !hasTransparentLayer);
2379 }
const QString COMPOSITE_OVER
void recursiveApplyNodes(NodePointer node, Functor func)
const QString & compositeOpId() const

References COMPOSITE_OVER, KisBaseNode::compositeOpId(), recursiveApplyNodes(), and KisNodeFacade::root.

◆ changeImageDefaultProjectionColor()

KRITAIMAGE_EXPORT void KisLayerUtils::changeImageDefaultProjectionColor ( KisImageSP image,
const KoColor & color )

◆ checkIsChildOf()

KRITAIMAGE_EXPORT bool KisLayerUtils::checkIsChildOf ( KisNodeSP node,
const KisNodeList & parents )

Definition at line 1545 of file kis_layer_utils.cpp.

1546 {
1547 KisNodeList nodeParents;
1548
1549 KisNodeSP parent = node->parent();
1550 while (parent) {
1551 nodeParents << parent;
1552 parent = parent->parent();
1553 }
1554
1555 foreach(KisNodeSP perspectiveParent, parents) {
1556 if (nodeParents.contains(perspectiveParent)) {
1557 return true;
1558 }
1559 }
1560
1561 return false;
1562 }
KisNodeWSP parent
Definition kis_node.cpp:86

References KisNode::parent.

◆ checkIsCloneOf()

KRITAIMAGE_EXPORT bool KisLayerUtils::checkIsCloneOf ( KisNodeSP node,
const KisNodeList & nodes )

Returns true if: o node is a clone of some layer in nodes o node is a clone any child layer of any layer in nodes o node is a clone of a clone of a ..., that in the end points to any layer in nodes of their children.

Definition at line 1564 of file kis_layer_utils.cpp.

1565 {
1566 bool result = false;
1567
1568 KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
1569 if (clone) {
1570 KisNodeSP cloneSource = KisNodeSP(clone->copyFrom());
1571
1572 Q_FOREACH(KisNodeSP subtree, nodes) {
1573 result =
1574 recursiveFindNode(subtree,
1575 [cloneSource](KisNodeSP node) -> bool
1576 {
1577 return node == cloneSource;
1578 });
1579
1580 if (!result) {
1581 result = checkIsCloneOf(cloneSource, nodes);
1582 }
1583
1584 if (result) {
1585 break;
1586 }
1587 }
1588 }
1589
1590 return result;
1591 }
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
KisNodeSP recursiveFindNode(KisNodeSP node, std::function< bool(KisNodeSP)> func)
KisLayerSP copyFrom

References checkIsCloneOf(), KisCloneLayer::copyFrom, KisSharedPtr< T >::data(), and recursiveFindNode().

◆ checkNodesDiffer()

template<typename T >
bool KisLayerUtils::checkNodesDiffer ( KisNodeList nodes,
std::function< T(KisNodeSP)> checkerFunc )

Definition at line 214 of file kis_layer_utils.h.

215 {
216 bool valueDiffers = false;
217 bool initialized = false;
218 T currentValue = T();
219 Q_FOREACH (KisNodeSP node, nodes) {
220 if (!initialized) {
221 currentValue = checkerFunc(node);
222 initialized = true;
223 } else if (currentValue != checkerFunc(node)) {
224 valueDiffers = true;
225 break;
226 }
227 }
228 return valueDiffers;
229 }

◆ convertToPaintLayer()

KRITAIMAGE_EXPORT std::future< KisNodeSP > KisLayerUtils::convertToPaintLayer ( KisImageSP image,
KisNodeSP src )

Definition at line 2406 of file kis_layer_utils.cpp.

2407 {
2408 //Initialize all operation dependencies.
2409 ConvertToPaintLayerInfoSP info( new ConvertToPaintLayerInfo(image, src) );
2410
2411 if (!info->hasTargetNode())
2413
2414 KisImageSignalVector emitSignals;
2415 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Convert to a Paint Layer"));
2416
2417 applicator.applyCommand(new SimpleAddNode(info->image(), info->targetNode(), info->insertionParent(), info->insertionPutAfter()), KisStrokeJobData::BARRIER);
2418
2419 if (info->frames().count() > 0) {
2420 Q_FOREACH(const int& frame, info->frames()) {
2421 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, false, info->storage));
2422 applicator.applyCommand(new RefreshDelayedUpdateLayers(info->sourceNodes()), KisStrokeJobData::BARRIER);
2423 applicator.applyCommand(new RefreshHiddenAreas(info->image(), info->sourceNode()), KisStrokeJobData::BARRIER);
2424 applicator.applyCommand(new AddNewFrame(info->targetNode(), frame, info->sourceNode()), KisStrokeJobData::BARRIER);
2425 applicator.applyCommand(new UploadProjectionToFrameCommand(info->sourceNode(), info->targetNode(), frame));
2426 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, true, info->storage));
2427 }
2428 }
2429
2430 applicator.applyCommand(new SimpleRemoveLayers(info->toRemove(), info->image()));
2431
2432 applicator.end();
2433
2434 return kismpl::then(applicator.successfullyCompletedFuture(),
2435 [node = info->targetNode()] (std::future<bool> completed) {
2436 return completed.get() ? node : KisNodeSP();
2437 });
2438 }
auto then(std::future< T > &&future, Function &&func) -> std::future< decltype(func(std::move(future)))>
std::future< void > make_ready_future()
The SwitchFrameCommand struct Switches to frame with undo/redo support.

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), kundo2_i18n(), kismpl::make_ready_future(), KisProcessingApplicator::NONE, KisProcessingApplicator::successfullyCompletedFuture(), and kismpl::then().

◆ fetchLayerActiveRasterFrameID()

int KisLayerUtils::fetchLayerActiveRasterFrameID ( KisNodeSP node)

Definition at line 2442 of file kis_layer_utils.cpp.

2443 {
2445 KisPaintDeviceSP paintDevice = node->paintDevice();
2446 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2447
2448 if (!paintDevice->keyframeChannel()) {
2449 return -1;
2450 }
2451
2452 const int activeTime = paintDevice->keyframeChannel()->activeKeyframeTime();
2453 KisRasterKeyframeSP keyframe = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(activeTime);
2455
2456 return keyframe->frameID();
2457 }
KisKeyframeSP activeKeyframeAt(int time) const
int activeKeyframeTime(int time) const
Get the time of the active keyframe. Useful for snapping any time to that of the most recent keyframe...
KisRasterKeyframeChannel * keyframeChannel() const
The KisRasterKeyframe class is a concrete subclass of KisKeyframe that wraps a physical raster image ...
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
virtual KisPaintDeviceSP paintDevice() const =0

References KisKeyframeChannel::activeKeyframeAt(), KisKeyframeChannel::activeKeyframeTime(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerActiveRasterFrameSpan()

KRITAIMAGE_EXPORT KisTimeSpan KisLayerUtils::fetchLayerActiveRasterFrameSpan ( KisNodeSP node,
const int time )

Definition at line 2472 of file kis_layer_utils.cpp.

2473 {
2475 KisPaintDeviceSP paintDevice = node->paintDevice();
2477 if (!paintDevice->keyframeChannel()) {
2478 return KisTimeSpan::infinite(0);
2479 }
2480
2481 return paintDevice->keyframeChannel()->affectedFrames(time);
2482 }
virtual KisTimeSpan affectedFrames(int time) const
Get the set of frames affected by any changes to the value or content of the active keyframe at the g...
static KisTimeSpan infinite(int start)

References KisKeyframeChannel::affectedFrames(), KisTimeSpan::infinite(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerActiveRasterFrameTime()

KRITAIMAGE_EXPORT int KisLayerUtils::fetchLayerActiveRasterFrameTime ( KisNodeSP node)

Definition at line 2459 of file kis_layer_utils.cpp.

2460 {
2462 KisPaintDeviceSP paintDevice = node->paintDevice();
2463 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2464
2465 if (!paintDevice->keyframeChannel()) {
2466 return -1;
2467 }
2468
2469 return paintDevice->keyframeChannel()->activeKeyframeTime();
2470 }

References KisKeyframeChannel::activeKeyframeTime(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerFrames()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerFrames ( KisNodeSP node)

Definition at line 1344 of file kis_layer_utils.cpp.

1344 {
1345 QSet<int> frames;
1346 Q_FOREACH(KisKeyframeChannel *channel, node->keyframeChannels()) {
1347 if (!channel) {
1348 continue;
1349 }
1350
1351 KisRasterKeyframeChannel *rasterChan = dynamic_cast<KisRasterKeyframeChannel*>(channel);
1352 if (rasterChan) {
1353 frames.unite(rasterChan->allKeyframeTimes());
1354 continue;
1355 }
1356
1357 KisScalarKeyframeChannel *scalarChan = dynamic_cast<KisScalarKeyframeChannel*>(channel);
1358 if (scalarChan) {
1359 const int initialKeyframe = scalarChan->firstKeyframeTime();
1360
1361 if (initialKeyframe == -1) {
1362 continue;
1363 }
1364
1365 const int lastKeyframe = scalarChan->lastKeyframeTime();
1366 KisTimeSpan currentSpan = scalarChan->identicalFrames(initialKeyframe);
1367 while (!currentSpan.isInfinite() && currentSpan.isValid() && currentSpan.start() < lastKeyframe) {
1368 frames.insert(currentSpan.start());
1369 currentSpan = scalarChan->identicalFrames(currentSpan.end() + 1);
1370 }
1371
1372 frames.insert(lastKeyframe);
1373 }
1374
1375 }
1376
1377 return frames;
1378 }
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.
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
The KisScalarKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisSca...
virtual KisTimeSpan identicalFrames(int time) const override
Get a span of times for which the channel gives identical results compared to frame at a given time....
int start() const
bool isInfinite() const
int end() const
bool isValid() const
QMap< QString, KisKeyframeChannel * > keyframeChannels

References KisKeyframeChannel::allKeyframeTimes(), KisTimeSpan::end(), KisKeyframeChannel::firstKeyframeTime(), KisScalarKeyframeChannel::identicalFrames(), KisTimeSpan::isInfinite(), KisTimeSpan::isValid(), KisBaseNode::keyframeChannels, KisKeyframeChannel::lastKeyframeTime(), and KisTimeSpan::start().

◆ fetchLayerFramesRecursive()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerFramesRecursive ( KisNodeSP rootNode)

Definition at line 1380 of file kis_layer_utils.cpp.

1380 {
1381 if (!rootNode->visible()) return QSet<int>();
1382
1383 QSet<int> frames = fetchLayerFrames(rootNode);
1384
1385 KisNodeSP node = rootNode->firstChild();
1386 while(node) {
1387 frames |= fetchLayerFramesRecursive(node);
1388 node = node->nextSibling();
1389 }
1390
1391 return frames;
1392 }
QSet< int > fetchLayerFrames(KisNodeSP node)
QSet< int > fetchLayerFramesRecursive(KisNodeSP rootNode)
virtual bool visible(bool recursive=false) const
KisNodeSP firstChild() const
Definition kis_node.cpp:361
KisNodeSP nextSibling() const
Definition kis_node.cpp:408

References fetchLayerFrames(), fetchLayerFramesRecursive(), KisNode::firstChild(), KisNode::nextSibling(), and KisBaseNode::visible().

◆ fetchLayerIdenticalRasterFrameTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchLayerIdenticalRasterFrameTimes ( KisNodeSP node,
const int & frameTime )

Definition at line 2484 of file kis_layer_utils.cpp.

2485 {
2486 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2487 KisPaintDeviceSP paintDevice = node->paintDevice();
2488 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2489 if (!paintDevice->keyframeChannel()) {
2490 return QSet<int>();
2491 }
2492
2493 return paintDevice->keyframeChannel()->clonesOf(node.data(), frameTime);
2494 }

References KisRasterKeyframeChannel::clonesOf(), KisSharedPtr< T >::data(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerRasterFrameTimesMatchingID()

QSet< int > KisLayerUtils::fetchLayerRasterFrameTimesMatchingID ( KisNodeSP node,
const int frameID )

Definition at line 2497 of file kis_layer_utils.cpp.

2497 {
2498 KIS_ASSERT(node);
2499 KisRasterKeyframeChannel* rasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false));
2500
2501 if (!rasterChannel) {
2502 return QSet<int>();
2503 }
2504
2505 return rasterChannel->timesForFrameID(frameID);
2506 }
static const KoID Raster
QSet< int > timesForFrameID(int frameID) const
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)

References KisBaseNode::getKeyframeChannel(), KIS_ASSERT, KisKeyframeChannel::Raster, and KisRasterKeyframeChannel::timesForFrameID().

◆ fetchLayerRasterIDsAtTimes()

QSet< int > KisLayerUtils::fetchLayerRasterIDsAtTimes ( KisNodeSP node,
const QSet< int > & times )

Definition at line 2508 of file kis_layer_utils.cpp.

2509 {
2510 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2511 KisPaintDeviceSP paintDevice = node->paintDevice();
2512 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2513 if (!paintDevice->keyframeChannel()) {
2514 return QSet<int>();
2515 }
2516
2517 QSet<int> frameIDs;
2518
2519 Q_FOREACH( const int& frame, times ) {
2521 frameIDs << raster->frameID();
2522 }
2523
2524 return frameIDs;
2525 }

References KisKeyframeChannel::activeKeyframeAt(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchLayerUniqueRasterTimesMatchingIDs()

QSet< int > KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs ( KisNodeSP node,
QSet< int > & frameIDs )

Definition at line 2539 of file kis_layer_utils.cpp.

2540 {
2541 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2542 KisPaintDeviceSP paintDevice = node->paintDevice();
2543 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2544 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice->framesInterface(), QSet<int>());
2545
2546 QSet<int> uniqueTimes;
2547
2548 Q_FOREACH( const int& id, frameIDs) {
2549 QSet<int> times = fetchLayerRasterFrameTimesMatchingID(node, id);
2550 if (times.count() > 0) {
2551 uniqueTimes.insert(*times.begin());
2552 }
2553 }
2554
2555 return uniqueTimes;
2556 }
KisPaintDeviceFramesInterface * framesInterface()
QSet< int > fetchLayerRasterFrameTimesMatchingID(KisNodeSP node, const int frameID)

References fetchLayerRasterFrameTimesMatchingID(), KisPaintDevice::framesInterface(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ fetchSelectionMasks()

void KisLayerUtils::fetchSelectionMasks ( KisNodeList mergedNodes,
QVector< KisSelectionMaskSP > & selectionMasks )

Definition at line 66 of file kis_layer_utils.cpp.

67 {
68 foreach (KisNodeSP node, mergedNodes) {
69
70 Q_FOREACH(KisNodeSP child, node->childNodes(QStringList("KisSelectionMask"), KoProperties())) {
71
72 KisSelectionMaskSP mask = qobject_cast<KisSelectionMask*>(child.data());
73 if (mask) {
74 selectionMasks.append(mask);
75 }
76 }
77 }
78 }
QList< KisNodeSP > childNodes(const QStringList &nodeTypes, const KoProperties &properties) const
Definition kis_node.cpp:439

References KisNode::childNodes(), and KisSharedPtr< T >::data().

◆ fetchUniqueFrameTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::fetchUniqueFrameTimes ( KisNodeSP node,
QSet< int > selectedTimes,
bool filterActiveFrameID )

Definition at line 2558 of file kis_layer_utils.cpp.

2559 {
2560 if (selectedTimes.isEmpty() || !node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id()))
2561 return selectedTimes;
2562
2563 // Convert a set of selected keyframe times into set of selected "frameIDs"...
2564 QSet<int> selectedFrameIDs = KisLayerUtils::fetchLayerRasterIDsAtTimes(node, selectedTimes);
2565
2566 if (filterActiveFrameID) {
2567 // Current frame was already filtered e.g. during filter preview in `KisFilterManager::apply`...
2568 // So let's remove it...
2569 const int currentActiveFrameID = KisLayerUtils::fetchLayerActiveRasterFrameID(node);
2570 selectedFrameIDs.remove(currentActiveFrameID);
2571 }
2572
2573 // Convert frameIDs to any arbitrary frame time associated with the frameID...
2574 QSet<int> uniqueFrameTimes = node->paintDevice()->framesInterface() ? KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs(node, selectedFrameIDs) : QSet<int>();
2575
2576 return uniqueFrameTimes;
2577 }
QString id() const
Definition KoID.cpp:63
int fetchLayerActiveRasterFrameID(KisNodeSP node)
QSet< int > fetchLayerUniqueRasterTimesMatchingIDs(KisNodeSP node, QSet< int > &frameIDs)
QSet< int > fetchLayerRasterIDsAtTimes(KisNodeSP node, const QSet< int > &times)
virtual bool supportsKeyframeChannel(const QString &id)

References fetchLayerActiveRasterFrameID(), fetchLayerRasterIDsAtTimes(), fetchLayerUniqueRasterTimesMatchingIDs(), KisPaintDevice::framesInterface(), KoID::id(), KisBaseNode::paintDevice(), KisKeyframeChannel::Raster, and KisBaseNode::supportsKeyframeChannel().

◆ filterInvisibleNodes()

KisNodeList KisLayerUtils::filterInvisibleNodes ( const KisNodeList & nodes,
KisNodeList * invisibleNodes,
KisNodeSP * putAfter )

When a layer is invisible and user-locked we should just skip it and do neither merge nor remove it.

Definition at line 1738 of file kis_layer_utils.cpp.

1739 {
1740 KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; }
1741 KIS_ASSERT_RECOVER(putAfter) { return nodes; }
1742
1743 KisNodeList visibleNodes;
1744 int putAfterIndex = -1;
1745
1746 Q_FOREACH(KisNodeSP node, nodes) {
1747 if (node->visible()) {
1748 visibleNodes << node;
1749 } else if (node->userLocked()) {
1754 } else {
1755 *invisibleNodes << node;
1756
1757 if (node == *putAfter) {
1758 putAfterIndex = visibleNodes.size() - 1;
1759 }
1760 }
1761 }
1762
1763 if (!visibleNodes.isEmpty() && putAfterIndex >= 0) {
1764 putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1);
1765 *putAfter = visibleNodes[putAfterIndex];
1766 }
1767
1768 return visibleNodes;
1769 }
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
bool userLocked() const

References KIS_ASSERT_RECOVER, KisBaseNode::userLocked(), and KisBaseNode::visible().

◆ filterMergeableNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::filterMergeableNodes ( KisNodeList & nodes,
bool allowMasks )

Definition at line 1593 of file kis_layer_utils.cpp.

1594 {
1595 KisNodeList::iterator it = nodes.begin();
1596
1597 while (it != nodes.end()) {
1598 if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) ||
1599 checkIsChildOf(*it, nodes)) {
1600 //qDebug() << "Skipping node" << ppVar((*it)->name());
1601 it = nodes.erase(it);
1602 } else {
1603 ++it;
1604 }
1605 }
1606 }
bool checkIsChildOf(KisNodeSP node, const KisNodeList &parents)

References checkIsChildOf().

◆ filterTimesForOnlyRasterKeyedTimes()

KRITAIMAGE_EXPORT QSet< int > KisLayerUtils::filterTimesForOnlyRasterKeyedTimes ( KisNodeSP node,
const QSet< int > & times )

Definition at line 2527 of file kis_layer_utils.cpp.

2528 {
2530 KisPaintDeviceSP paintDevice = node->paintDevice();
2531 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, times);
2532 if (!paintDevice->keyframeChannel()) {
2533 return times;
2534 }
2535
2536 return paintDevice->keyframeChannel()->allKeyframeTimes().intersect(times);
2537 }

References KisKeyframeChannel::allKeyframeTimes(), KisPaintDevice::keyframeChannel(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and KisBaseNode::paintDevice().

◆ filterUnlockedNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::filterUnlockedNodes ( KisNodeList & nodes)

Definition at line 1771 of file kis_layer_utils.cpp.

1772 {
1773 KisNodeList::iterator it = nodes.begin();
1774
1775 while (it != nodes.end()) {
1776 if ((*it)->userLocked()) {
1777 it = nodes.erase(it);
1778 } else {
1779 ++it;
1780 }
1781 }
1782 }

◆ findImageByHierarchy()

KRITAIMAGE_EXPORT KisImageSP KisLayerUtils::findImageByHierarchy ( KisNodeSP node)

Definition at line 2271 of file kis_layer_utils.cpp.

2272 {
2273 while (node) {
2274 const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data());
2275 if (layer) {
2276 return layer->image();
2277 }
2278
2279 node = node->parent();
2280 }
2281
2282 return 0;
2283 }
KisImageWSP image

References KisSharedPtr< T >::data(), KisBaseNode::image, and KisNode::parent.

◆ findIsolationRoot()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findIsolationRoot ( KisNodeSP node)

Definition at line 2228 of file kis_layer_utils.cpp.

2229 {
2230 KisImageSP image = node->image();
2231 if (image)
2232 return image->isolationRootNode();
2233 return nullptr;
2234 }
KisNodeSP isolationRootNode() const

References KisBaseNode::image, and KisImage::isolationRootNode().

◆ findNodeByName()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findNodeByName ( KisNodeSP root,
const QString & name )

Definition at line 2220 of file kis_layer_utils.cpp.

2221 {
2222 return recursiveFindNode(root,
2223 [name] (KisNodeSP node) {
2224 return node->name() == name;
2225 });
2226 }

References KisBaseNode::name(), and recursiveFindNode().

◆ findNodeByType()

template<class T >
T * KisLayerUtils::findNodeByType ( KisNodeSP root)

Definition at line 269 of file kis_layer_utils.h.

269 {
270 return dynamic_cast<T*>(recursiveFindNode(root, [] (KisNodeSP node) {
271 return bool(dynamic_cast<T*>(node.data()));
272 }).data());
273 }

References KisSharedPtr< T >::data(), and recursiveFindNode().

◆ findNodeByUuid()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findNodeByUuid ( KisNodeSP root,
const QUuid & uuid )

Recursively searches for a node with specified Uuid

Definition at line 2194 of file kis_layer_utils.cpp.

2195 {
2196 return recursiveFindNode(root,
2197 [uuid] (KisNodeSP node) {
2198 return node->uuid() == uuid;
2199 });
2200 }
QUuid uuid() const

References recursiveFindNode(), and KisBaseNode::uuid().

◆ findNodesByName()

KRITAIMAGE_EXPORT QList< KisNodeSP > KisLayerUtils::findNodesByName ( KisNodeSP root,
const QString & name,
bool recursive,
bool partialMatch )

Definition at line 2202 of file kis_layer_utils.cpp.

2203 {
2204 KisNodeList nodeList;
2205 KisNodeSP child = root->firstChild();
2206
2207 while (child) {
2208 if (name.isEmpty() || (!partialMatch && child->name() == name) || (partialMatch && child->name().contains(name, Qt::CaseInsensitive))) {
2209 nodeList << child;
2210 }
2211 if (recursive && child->childCount() > 0) {
2212 nodeList << findNodesByName(child, name, recursive, partialMatch);
2213 }
2214 child = child->nextSibling();
2215 }
2216
2217 return nodeList;
2218 }
quint32 childCount() const
Definition kis_node.cpp:414

References KisNode::childCount(), findNodesByName(), KisNode::firstChild(), KisBaseNode::name(), and KisNode::nextSibling().

◆ findNodesWithProps()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::findNodesWithProps ( KisNodeSP root,
const KoProperties & props,
bool excludeRoot )

Definition at line 1721 of file kis_layer_utils.cpp.

1722 {
1723 KisNodeList nodes;
1724
1725 if ((!excludeRoot || root->parent()) && root->check(props)) {
1726 nodes << root;
1727 }
1728
1729 KisNodeSP node = root->firstChild();
1730 while (node) {
1731 nodes += findNodesWithProps(node, props, excludeRoot);
1732 node = node->nextSibling();
1733 }
1734
1735 return nodes;
1736 }
bool check(const KoProperties &properties) const

References KisBaseNode::check(), findNodesWithProps(), KisNode::firstChild(), KisNode::nextSibling(), and KisNode::parent.

◆ findRoot()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findRoot ( KisNodeSP node)

Definition at line 2339 of file kis_layer_utils.cpp.

2340 {
2341 if (!node) return node;
2342
2343 while (node->parent()) {
2344 node = node->parent();
2345 }
2346 return node;
2347 }

References KisNode::parent.

◆ flattenImage()

KRITAIMAGE_EXPORT void KisLayerUtils::flattenImage ( KisImageSP image,
KisNodeSP activeNode,
MergeFlags flags )

Definition at line 2144 of file kis_layer_utils.cpp.

2145 {
2146 if (!activeNode) {
2147 activeNode = image->root()->lastChild();
2148 }
2149
2150
2151 KisNodeList mergedNodes;
2152 mergedNodes << image->root();
2153
2154 mergeMultipleLayersImpl(image, mergedNodes, activeNode,
2155 true, kundo2_i18n("Flatten Image"),
2156 true, QString(),
2157 flags);
2158 }
KisNodeSP lastChild() const
Definition kis_node.cpp:367

References kundo2_i18n(), KisNode::lastChild(), mergeMultipleLayersImpl(), and KisNodeFacade::root.

◆ flattenLayer()

KRITAIMAGE_EXPORT void KisLayerUtils::flattenLayer ( KisImageSP image,
KisLayerSP layer,
MergeFlags flags )

Definition at line 2130 of file kis_layer_utils.cpp.

2131 {
2132 if (!layer->childCount() && !layer->layerStyle())
2133 return;
2134
2135 KisNodeList mergedNodes;
2136 mergedNodes << layer;
2137
2138 mergeMultipleLayersImpl(image, mergedNodes, layer,
2139 true, kundo2_i18n("Flatten Layer"),
2140 true, QString(),
2141 flags);
2142 }
void mergeMultipleLayersImpl(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, bool flattenSingleLayer, const KUndo2MagicString &actionName, bool cleanupNodes=true, const QString layerName=QString(), MergeFlags flags=None)
KisPSDLayerStyleSP layerStyle
Definition kis_layer.cc:171

References KisNode::childCount(), kundo2_i18n(), KisLayer::layerStyle, and mergeMultipleLayersImpl().

◆ forceAllDelayedNodesUpdate()

KRITAIMAGE_EXPORT void KisLayerUtils::forceAllDelayedNodesUpdate ( KisNodeSP root)

Definition at line 2236 of file kis_layer_utils.cpp.

2237 {
2239 [] (KisNodeSP node) {
2240 KisDelayedUpdateNodeInterface *delayedUpdate =
2241 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2242 if (delayedUpdate) {
2243 delayedUpdate->forceUpdateTimedNode();
2244 }
2245 });
2246 }
The KisDelayedUpdateNodeInterface class is an interface for nodes that delay their real updates with ...
virtual void forceUpdateTimedNode()=0
forceUpdateTimedNode forces the node to regenerate its project. The update might be asynchronous,...

References KisSharedPtr< T >::data(), KisDelayedUpdateNodeInterface::forceUpdateTimedNode(), and recursiveApplyNodes().

◆ forceAllHiddenOriginalsUpdate()

KRITAIMAGE_EXPORT void KisLayerUtils::forceAllHiddenOriginalsUpdate ( KisNodeSP root)

Definition at line 2259 of file kis_layer_utils.cpp.

2260 {
2262 [] (KisNodeSP node) {
2263 KisCroppedOriginalLayerInterface *croppedUpdate =
2264 dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data());
2265 if (croppedUpdate) {
2266 croppedUpdate->forceUpdateHiddenAreaOnOriginal();
2267 }
2268 });
2269 }
virtual void forceUpdateHiddenAreaOnOriginal()=0

References KisSharedPtr< T >::data(), KisCroppedOriginalLayerInterface::forceUpdateHiddenAreaOnOriginal(), and recursiveApplyNodes().

◆ hasDelayedNodeWithUpdates()

KRITAIMAGE_EXPORT bool KisLayerUtils::hasDelayedNodeWithUpdates ( KisNodeSP root)

Definition at line 2248 of file kis_layer_utils.cpp.

2249 {
2250 return recursiveFindNode(root,
2251 [] (KisNodeSP node) {
2252 KisDelayedUpdateNodeInterface *delayedUpdate =
2253 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2254
2255 return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false;
2256 });
2257 }
virtual bool hasPendingTimedUpdates() const =0

References KisSharedPtr< T >::data(), KisDelayedUpdateNodeInterface::hasPendingTimedUpdates(), and recursiveFindNode().

◆ mergeDown()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeDown ( KisImageSP image,
KisLayerSP layer,
const KisMetaData::MergeStrategy * strategy,
MergeFlags flags )
See also
a comment in mergeMultipleLayersImpl()

Save the original time before we start switching is with asynchronous SwitchFrameCommand.

When switching frames we need to update the entire image, not only the new extent of the layer, hence we pass refresh_entire_image to the command to make sure that the entire image bounds rect is added to the update rect

If source layer is not animated, then just merge that into the current frame to avoid unintentional destruction of the animation on the layer below. To merge the source into all the frames, just make the source animated.

See https://bugs.kde.org/show_bug.cgi?id=475550

Definition at line 1420 of file kis_layer_utils.cpp.

1421 {
1422 if (!layer->prevSibling()) return;
1423
1424 // XXX: this breaks if we allow free mixing of masks and layers
1425 KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
1426
1427 while (prevLayer && prevLayer->isFakeNode()) {
1428 prevLayer = qobject_cast<KisLayer*>(prevLayer->prevSibling().data());
1429 }
1430
1431 if (!prevLayer) return;
1432
1433 if (!layer->visible() && !prevLayer->visible()) {
1434 return;
1435 }
1436
1437 KisImageSignalVector emitSignals;
1438 KisProcessingApplicator applicator(image, 0,
1440 emitSignals,
1441 kundo2_i18n("Merge Down"));
1442
1443 if (layer->visible() && prevLayer->visible()) {
1444 MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer, flags));
1445
1446 // disable key strokes on all colorize masks, all onion skins on
1447 // paint layers and wait until update is finished with a barrier
1448 applicator.applyCommand(new DisableColorizeKeyStrokes(info));
1449 applicator.applyCommand(new DisableOnionSkins(info));
1450 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1451
1452 applicator.applyCommand(new KeepMergedNodesSelected(info, false));
1453 applicator.applyCommand(new FillSelectionMasks(info));
1454 applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER);
1455
1456 // NOTE: shape layer may have emitted spontaneous jobs during layer creation,
1457 // wait for them to complete!
1458 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1459 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1460
1461 // in two-layer mode we disable pass through only when the destination layer
1462 // is not a group layer
1463 applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true));
1464 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1465
1466 if (info->frames.size() > 0) {
1471 const int currentTimeOnStart = info->image->animationInterface()->currentTime();
1472
1473 foreach (int frame, info->frames) {
1474 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1475
1476 applicator.applyCommand(new AddNewFrame(info, frame));
1483 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1484 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1485
1494 const bool skipMergingSourceLayer = !layer->isAnimated() &&
1495 frame != currentTimeOnStart;
1496
1497 applicator.applyCommand(new MergeLayers(info, skipMergingSourceLayer), KisStrokeJobData::BARRIER);
1498
1499 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage), KisStrokeJobData::BARRIER);
1500 }
1501 } else {
1502 applicator.applyCommand(new RefreshHiddenAreas(info));
1503 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1504 applicator.applyCommand(new MergeLayers(info, false), KisStrokeJobData::BARRIER);
1505 }
1506
1507 applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1508 applicator.applyCommand(new CleanUpNodes(info, layer),
1511 applicator.applyCommand(new KeepMergedNodesSelected(info, true));
1512 } else if (layer->visible()) {
1513 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1514 layer, KisNodeSP(),
1515 image, false));
1516
1517 applicator.applyCommand(
1518 new SimpleRemoveLayers(KisNodeList() << prevLayer,
1519 image),
1522
1523 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1524 KisNodeSP(), layer,
1525 image, true));
1526 } else if (prevLayer->visible()) {
1527 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1528 layer, KisNodeSP(),
1529 image, false));
1530
1531 applicator.applyCommand(
1532 new SimpleRemoveLayers(KisNodeList() << layer,
1533 image),
1536
1537 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1538 KisNodeSP(), prevLayer,
1539 image, true));
1540 }
1541
1542 applicator.end();
1543 }
QList< KisNodeSP > KisNodeList
Definition kis_types.h:264
QSharedPointer< MergeDownInfo > MergeDownInfoSP
bool isAnimated() const
virtual bool isFakeNode() const
KisNodeSP prevSibling() const
Definition kis_node.cpp:402

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisSharedPtr< T >::data(), KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, KisBaseNode::isAnimated(), KisBaseNode::isFakeNode(), kundo2_i18n(), KisProcessingApplicator::NONE, KisNode::prevSibling(), KisLayerUtils::RefreshHiddenAreas::refresh_entire_image, KisStrokeJobData::SEQUENTIAL, and KisBaseNode::visible().

◆ mergeMultipleLayers()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeMultipleLayers ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
MergeFlags flags )

Definition at line 2014 of file kis_layer_utils.cpp.

2015 {
2016 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2017 false, kundo2_i18n("Merge Selected Nodes"),
2018 true, QString(),
2019 flags);
2020 }

References kundo2_i18n(), and mergeMultipleLayersImpl().

◆ mergeMultipleLayersImpl()

void KisLayerUtils::mergeMultipleLayersImpl ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
bool flattenSingleLayer,
const KUndo2MagicString & actionName,
bool cleanupNodes = true,
const QString layerName = QString(),
MergeFlags flags = None )

There might be two approaches for merging multiple layers:

1) Consider the selected nodes as a distinct "group" and merge them as if they were isolated from the rest of the image. The key point of this approach is that the look of the image will change, when merging "weird" layers, like adjustment layers or layers with non-normal blending mode.

2) Merge layers in a way to keep the look of the image as unchanged as possible. With this approach one uses a few heuristics:

  • when merging multiple layers with non-normal (but equal) blending mode, first merge these layers together using Normal blending mode, then set blending mode of the result to the original blending mode
  • when merging multiple layers with different blending modes or layer styles, they are first rasterized, and then laid over each other with their own composite op. The blending mode of the final layer is set to Normal, so the user could clearly see that he should choose the correct blending mode.

Krita uses the second approach: after merge operation, the image should look as if nothing has happened (if it is technically possible).

We have reached the root of the layer hierarchy and didn't manage to find a node that was editable enough for putting our merged result into it. That shouldn't happen in normal circumstances, unless the user chose to make the root layer visible and lock it manually.

When switching frames we need to update the entire image, not only the new extent of the layer, hence we pass refresh_entire_image to the command to make sure that the entire image bounds rect is added to the update rect

Definition at line 1871 of file kis_layer_utils.cpp.

1875 {
1876 if (!putAfter) {
1877 putAfter = mergedNodes.first();
1878 }
1879
1880 filterMergeableNodes(mergedNodes);
1881 {
1882 KisNodeList tempNodes;
1883 std::swap(mergedNodes, tempNodes);
1884 sortMergeableNodes(image->root(), tempNodes, mergedNodes);
1885 }
1886
1887 if (mergedNodes.size() <= 1 &&
1888 (!flattenSingleLayer && mergedNodes.size() == 1)) return;
1889
1890 KisImageSignalVector emitSignals;
1891 emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes);
1892
1893
1894
1895 KisNodeList originalNodes = mergedNodes;
1896 KisNodeList invisibleNodes;
1897 mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter);
1898
1899 if (mergedNodes.isEmpty()) return;
1900
1901
1902 // make sure we don't add the new layer into a locked group
1904 while (putAfter->parent() && !putAfter->parent()->isEditable()) {
1905 putAfter = putAfter->parent();
1906 }
1907
1915 if (!putAfter->parent()) {
1916 return;
1917 }
1918
1919 KisProcessingApplicator applicator(image, 0,
1921 emitSignals,
1922 actionName);
1923
1924
1925 if (!invisibleNodes.isEmpty() && cleanupNodes) {
1926
1927 /* If the putAfter node is invisible,
1928 * we should instead pick one of the nodes
1929 * to be merged to avoid a null putAfter
1930 * after we remove all invisible layers from
1931 * the image.
1932 * (The assumption is that putAfter is among
1933 * the layers to merge, so if it's invisible,
1934 * it's going to be removed)
1935 */
1936 if (!putAfter->visible()){
1937 putAfter = mergedNodes.first();
1938 }
1939
1940 applicator.applyCommand(
1941 new SimpleRemoveLayers(invisibleNodes,
1942 image),
1945 }
1946
1947 if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) {
1948 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, flags));
1949
1950 // disable key strokes on all colorize masks, all onion skins on
1951 // paint layers and wait until update is finished with a barrier
1952 //
1953 // when doing "new layer from visible" we should undo these changes
1954 // before the action stops, because the source layers are **not**
1955 // removed as a result of this action
1956 applicator.applyCommand(
1957 new EphemeralCommandsWrapper(info,
1958 {
1959 new DisableColorizeKeyStrokes(info),
1960 new DisableOnionSkins(info),
1961 new DisablePassThroughForHeadsOnly(info)
1962 },
1963 cleanupNodes));
1964 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1965
1966 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false));
1967 applicator.applyCommand(new FillSelectionMasks(info));
1968 applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER);
1969 applicator.applyCommand(new EphemeralCommandsWrapper(info, { new DisableExtraCompositing(info) } , cleanupNodes));
1970 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1971
1972 if (!info->frames.isEmpty()) {
1973 foreach (int frame, info->frames) {
1974 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1975
1976 applicator.applyCommand(new AddNewFrame(info, frame));
1983 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1984 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1985 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1986
1987 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
1988 }
1989 } else {
1990 applicator.applyCommand(new RefreshHiddenAreas(info));
1991 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1992 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
1993 }
1994
1995 //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1996 if (cleanupNodes){
1997 applicator.applyCommand(new CleanUpNodes(info, putAfter, flattenSingleLayer),
2000 } else {
2001 applicator.applyCommand(new UndoEphemeralCommands(info));
2002 applicator.applyCommand(new InsertNode(info, putAfter),
2005 }
2006
2007 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true));
2008 }
2009
2010 applicator.end();
2011
2012 }
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
KisNodeList filterInvisibleNodes(const KisNodeList &nodes, KisNodeList *invisibleNodes, KisNodeSP *putAfter)
QSharedPointer< MergeMultipleInfo > MergeMultipleInfoSP
bool isEditable(bool checkVisibility=true) const

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, filterInvisibleNodes(), filterMergeableNodes(), KisBaseNode::isEditable(), KIS_SAFE_ASSERT_RECOVER_RETURN, KisProcessingApplicator::NONE, KisNode::parent, KisLayerUtils::RefreshHiddenAreas::refresh_entire_image, KisNodeFacade::root, KisStrokeJobData::SEQUENTIAL, sortMergeableNodes(), and KisBaseNode::visible().

◆ mergeMultipleNodes()

KRITAIMAGE_EXPORT void KisLayerUtils::mergeMultipleNodes ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter,
MergeFlags flags = None )

Same as mergeMultipleLayers() but tries to merge masks with tryMergeSelectionMasks() first.

Definition at line 2022 of file kis_layer_utils.cpp.

2023 {
2024 if (!tryMergeSelectionMasks(image, mergedNodes, putAfter)) {
2025 mergeMultipleLayers(image, mergedNodes, putAfter, flags);
2026 }
2027 }
bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image)
void mergeMultipleLayers(KisImageSP image, KisNodeList mergedNodes, KisNodeSP putAfter, MergeFlags flags)

References mergeMultipleLayers(), and tryMergeSelectionMasks().

◆ newLayerFromVisible()

KRITAIMAGE_EXPORT void KisLayerUtils::newLayerFromVisible ( KisImageSP image,
KisNodeSP putAfter,
MergeFlags flags )

Definition at line 2029 of file kis_layer_utils.cpp.

2030 {
2031 KisNodeList mergedNodes;
2032 mergedNodes << image->root();
2033
2034 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2035 true, kundo2_i18n("New From Visible"),
2036 false, i18nc("New layer created from all the visible layers", "Visible"),
2037 flags);
2038 }

References kundo2_i18n(), mergeMultipleLayersImpl(), and KisNodeFacade::root.

◆ recursiveApplyNodes()

template<typename NodePointer , typename Functor >
void KisLayerUtils::recursiveApplyNodes ( NodePointer node,
Functor func )

Applies func to node and all its children recursively

Definition at line 235 of file kis_layer_utils.h.

236 {
237 func(node);
238
239 node = node->firstChild();
240 while (node) {
241 recursiveApplyNodes(node, func);
242 node = node->nextSibling();
243 }
244 }

References recursiveApplyNodes().

◆ recursiveFindNode()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::recursiveFindNode ( KisNodeSP node,
std::function< bool(KisNodeSP)> func )

Walks through node and all its children recursively until func returns true. When func returns true, the node is considered to be found, the search is stopped and the found node is returned to the caller.

Definition at line 2176 of file kis_layer_utils.cpp.

2177 {
2178 if (func(node)) {
2179 return node;
2180 }
2181
2182 node = node->firstChild();
2183 while (node) {
2184 KisNodeSP resultNode = recursiveFindNode(node, func);
2185 if (resultNode) {
2186 return resultNode;
2187 }
2188 node = node->nextSibling();
2189 }
2190
2191 return 0;
2192 }

References KisNode::firstChild(), KisNode::nextSibling(), and recursiveFindNode().

◆ recursiveTightNodeVisibleBounds()

KRITAIMAGE_EXPORT QRect KisLayerUtils::recursiveTightNodeVisibleBounds ( KisNodeSP rootNode)

Definition at line 2330 of file kis_layer_utils.cpp.

2331 {
2332 QRect exactBounds;
2333 recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) {
2334 exactBounds |= node->projectionPlane()->tightUserVisibleBounds();
2335 });
2336 return exactBounds;
2337 }
virtual KisAbstractProjectionPlaneSP projectionPlane() const
Definition kis_node.cpp:240

References KisNode::projectionPlane(), and recursiveApplyNodes().

◆ refreshHiddenAreaAsync()

KRITAIMAGE_EXPORT void KisLayerUtils::refreshHiddenAreaAsync ( KisImageSP image,
KisNodeSP rootNode,
const QRect & preparedArea )

Definition at line 2326 of file kis_layer_utils.cpp.

2326 {
2327 Private::refreshHiddenAreaAsync(image, rootNode, preparedArea, QRect());
2328 }

References KisLayerUtils::Private::refreshHiddenAreaAsync().

◆ sortAndFilterAnyMergeableNodesSafe()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortAndFilterAnyMergeableNodesSafe ( const KisNodeList & nodes,
KisImageSP image )

Definition at line 1685 of file kis_layer_utils.cpp.

1685 {
1686 KisNodeList filteredNodes = nodes;
1687 KisNodeList sortedNodes;
1688
1689 KisLayerUtils::filterMergeableNodes(filteredNodes, true);
1690
1691 bool haveExternalNodes = false;
1692 Q_FOREACH (KisNodeSP node, nodes) {
1693 if (node->graphListener() != image->root()->graphListener()) {
1694 haveExternalNodes = true;
1695 break;
1696 }
1697 }
1698
1699 if (!haveExternalNodes) {
1700 KisLayerUtils::sortMergeableNodes(image->root(), filteredNodes, sortedNodes);
1701 } else {
1702 sortedNodes = filteredNodes;
1703 }
1704
1705 return sortedNodes;
1706 }
void sortMergeableNodes(KisNodeSP root, KisNodeList &inputNodes, KisNodeList &outputNodes)
void filterMergeableNodes(KisNodeList &nodes, bool allowMasks)
KisNodeGraphListener * graphListener
Definition kis_node.cpp:87

References filterMergeableNodes(), KisNode::graphListener, KisNodeFacade::root, and sortMergeableNodes().

◆ sortAndFilterMergeableInternalNodes()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortAndFilterMergeableInternalNodes ( KisNodeList nodes,
bool allowMasks )

Definition at line 1640 of file kis_layer_utils.cpp.

1641 {
1642 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1643
1644 KisNodeSP root;
1645 Q_FOREACH(KisNodeSP node, nodes) {
1646 KisNodeSP localRoot = node;
1647 while (localRoot->parent()) {
1648 localRoot = localRoot->parent();
1649 }
1650
1651 if (!root) {
1652 root = localRoot;
1653 }
1654 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1655 }
1656
1657 KisNodeList result;
1658 sortMergeableNodes(root, nodes, result);
1659 filterMergeableNodes(result, allowMasks);
1660 return result;
1661 }
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126

References filterMergeableNodes(), KIS_SAFE_ASSERT_RECOVER, KisNode::parent, and sortMergeableNodes().

◆ sortMergeableInternalNodes()

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortMergeableInternalNodes ( KisNodeList nodes)

Definition at line 1663 of file kis_layer_utils.cpp.

1664 {
1665 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1666
1667 KisNodeSP root;
1668 Q_FOREACH(KisNodeSP node, nodes) {
1669 KisNodeSP localRoot = node;
1670 while (localRoot->parent()) {
1671 localRoot = localRoot->parent();
1672 }
1673
1674 if (!root) {
1675 root = localRoot;
1676 }
1677 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1678 }
1679
1680 KisNodeList result;
1681 sortMergeableNodes(root, nodes, result);
1682 return result;
1683 }

References KIS_SAFE_ASSERT_RECOVER, KisNode::parent, and sortMergeableNodes().

◆ sortMergeableNodes() [1/3]

void KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
KisNodeList & inputNodes,
KisNodeList & outputNodes )

By the end of recursion inputNodes must be empty

Definition at line 1608 of file kis_layer_utils.cpp.

1609 {
1610 KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root);
1611
1612 if (it != inputNodes.end()) {
1613 outputNodes << *it;
1614 inputNodes.erase(it);
1615 }
1616
1617 if (inputNodes.isEmpty()) {
1618 return;
1619 }
1620
1621 KisNodeSP child = root->firstChild();
1622 while (child) {
1623 sortMergeableNodes(child, inputNodes, outputNodes);
1624 child = child->nextSibling();
1625 }
1626
1630 KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty());
1631 }
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
KisNodeListSP inputNodes(KisImageSP image, InputLayerMode inputMode, KisNodeSP currentNode)

References KisNode::firstChild(), KIS_ASSERT_RECOVER_NOOP, KisNode::nextSibling(), KisNode::parent, and sortMergeableNodes().

◆ sortMergeableNodes() [2/3]

KRITAIMAGE_EXPORT KisNodeList KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
KisNodeList nodes )

Definition at line 1633 of file kis_layer_utils.cpp.

1634 {
1635 KisNodeList result;
1636 sortMergeableNodes(root, nodes, result);
1637 return result;
1638 }

References sortMergeableNodes().

◆ sortMergeableNodes() [3/3]

KRITAIMAGE_EXPORT void KisLayerUtils::sortMergeableNodes ( KisNodeSP root,
QList< KisNodeSP > & inputNodes,
QList< KisNodeSP > & outputNodes )

◆ splitAlphaToMask()

KRITAIMAGE_EXPORT void KisLayerUtils::splitAlphaToMask ( KisImageSP image,
KisNodeSP node,
const QString & maskName )

Definition at line 2381 of file kis_layer_utils.cpp.

2382 {
2383 SplitAlphaToMaskInfoSP info( new SplitAlphaToMaskInfo(node->image(), node, maskName) );
2384
2385 KisImageSignalVector emitSignals;
2386 KisProcessingApplicator applicator(image, 0,
2388 emitSignals,
2389 kundo2_i18n("Split Alpha into a Mask"));
2390
2391 applicator.applyCommand(new SimpleAddNode(info->image, info->getMask(), info->node), KisStrokeJobData::BARRIER);
2392 applicator.applyCommand(new InitSplitAlphaSelectionMask(info));
2393 if (info->frames.count() > 0) {
2394 Q_FOREACH(const int& frame, info->frames) {
2395 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
2396 applicator.applyCommand(new AddNewFrame(info->getMask(), frame, info->node));
2397 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2398 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
2399 }
2400 } else {
2401 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2402 }
2403 applicator.end();
2404 }

References KisProcessingApplicator::applyCommand(), KisStrokeJobData::BARRIER, KisProcessingApplicator::end(), KisBaseNode::image, kundo2_i18n(), and KisProcessingApplicator::NONE.

◆ splitNonRemovableNodes()

void KisLayerUtils::splitNonRemovableNodes ( KisNodeList & nodesToRemove,
KisNodeList & _nodesToHide )

Definition at line 1111 of file kis_layer_utils.cpp.

1112 {
1113 QSet<KisNodeSP> nodesToHide;
1114 QSet<KisNodeSP> extraNodesToRemove;
1115
1116 for (auto it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) {
1117 KisNodeSP root = *it;
1119
1120 if (!root->isEditable(false)) {
1121 nodesToHide.insert(root);
1122 } else {
1123 bool rootNeedsCarefulRemoval = false;
1124
1125 recursiveApplyNodes(root,
1126 [root, &nodesToHide, &rootNeedsCarefulRemoval] (KisNodeSP node) {
1127 if (!node->isEditable(false)) {
1128 while (node != root) {
1129 nodesToHide.insert(node);
1130 node = node->parent();
1131 KIS_SAFE_ASSERT_RECOVER_BREAK(node);
1132 }
1133 nodesToHide.insert(root);
1134 rootNeedsCarefulRemoval = true;
1135 }
1136 });
1137
1138 if (rootNeedsCarefulRemoval) {
1140 [&extraNodesToRemove] (KisNodeSP node) {
1141 extraNodesToRemove.insert(node);
1142 });
1143 }
1144 }
1145 }
1146 nodesToRemove += KisNodeList(extraNodesToRemove.begin(), extraNodesToRemove.end());
1147 KritaUtils::filterContainer<KisNodeList>(nodesToRemove,
1148 [nodesToHide](KisNodeSP node) {
1149 return !nodesToHide.contains(node);
1150 });
1151 _nodesToHide = KisNodeList(nodesToHide.begin(), nodesToHide.end());
1152 }
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KisBaseNode::isEditable(), KIS_SAFE_ASSERT_RECOVER_NOOP, recursiveApplyNodes(), and KisBaseNode::visible().

◆ tryMergeSelectionMasks()

KRITAIMAGE_EXPORT bool KisLayerUtils::tryMergeSelectionMasks ( KisImageSP image,
KisNodeList mergedNodes,
KisNodeSP putAfter )

Definition at line 2091 of file kis_layer_utils.cpp.

2092 {
2093 QList<KisSelectionMaskSP> selectionMasks;
2094
2095 for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) {
2096 KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data());
2097 if (!mask) {
2098 it = mergedNodes.erase(it);
2099 } else {
2100 selectionMasks.append(mask);
2101 ++it;
2102 }
2103 }
2104
2105 if (mergedNodes.isEmpty()) return false;
2106
2107 KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data());
2108 KIS_ASSERT_RECOVER(parentLayer) { return 0; }
2109
2110 KisImageSignalVector emitSignals;
2111
2112 KisProcessingApplicator applicator(image, 0,
2114 emitSignals,
2115 kundo2_i18n("Merge Selection Masks"));
2116
2117 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, None));
2118
2119
2120 applicator.applyCommand(new MergeSelectionMasks(info, putAfter));
2121 applicator.applyCommand(new CleanUpNodes(info, putAfter),
2124 applicator.applyCommand(new ActivateSelectionMask(info));
2125 applicator.end();
2126
2127 return true;
2128 }

References KisProcessingApplicator::applyCommand(), KisProcessingApplicator::end(), KisStrokeJobData::EXCLUSIVE, KIS_ASSERT_RECOVER, kundo2_i18n(), None, KisProcessingApplicator::NONE, and KisStrokeJobData::SEQUENTIAL.

◆ updateFrameJobs()

void KisLayerUtils::updateFrameJobs ( FrameJobs * jobs,
KisNodeSP node )

Definition at line 1394 of file kis_layer_utils.cpp.

1394 {
1395 QSet<int> frames = fetchLayerFrames(node);
1396 frames = fetchUniqueFrameTimes(node, frames, false);
1397
1398 if (frames.isEmpty()) {
1399 (*jobs)[0].insert(node);
1400 } else {
1401 foreach (int frame, frames) {
1402 (*jobs)[frame].insert(node);
1403 }
1404 }
1405 }
QSet< int > fetchUniqueFrameTimes(KisNodeSP node, QSet< int > selectedTimes, bool filterActiveFrameID)

References fetchLayerFrames(), and fetchUniqueFrameTimes().

◆ updateFrameJobsRecursive()

void KisLayerUtils::updateFrameJobsRecursive ( FrameJobs * jobs,
KisNodeSP rootNode )

Definition at line 1407 of file kis_layer_utils.cpp.

1407 {
1408 updateFrameJobs(jobs, rootNode);
1409
1410 KisNodeSP node = rootNode->firstChild();
1411 while(node) {
1412 updateFrameJobsRecursive(jobs, node);
1413 node = node->nextSibling();
1414 }
1415 }
void updateFrameJobs(FrameJobs *jobs, KisNodeSP node)
void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode)

References KisNode::firstChild(), KisNode::nextSibling(), updateFrameJobs(), and updateFrameJobsRecursive().