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 1740 of file kis_layer_utils.cpp.

1741 {
1742 if (!KisImageConfig(true).renameDuplicatedLayers()) { return; }
1743
1744 const QString prefix = i18n("Copy of");
1745 QString newName = node->name();
1746 if (!newName.startsWith(prefix)) {
1747 newName = QString("%1 %2").arg(prefix).arg(newName);
1748 node->setName(newName);
1749 }
1750 }
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 2380 of file kis_layer_utils.cpp.

2381 {
2382 int numLayers = 0;
2383 bool hasNonNormalLayers = false;
2384 bool hasTransparentLayer = false;
2385
2386
2387 recursiveApplyNodes(image->root(),
2388 [&numLayers, &hasNonNormalLayers, &hasTransparentLayer, image] (KisNodeSP node) {
2389 if (!node->inherits("KisLayer")) return;
2390
2391 numLayers++;
2392
2393 if (node->exactBounds().isEmpty()) return;
2394
2395 // this is only an approximation! it is not exact!
2396 if (!hasTransparentLayer &&
2397 node->exactBounds() != image->bounds()) {
2398
2399 hasTransparentLayer = true;
2400 }
2401
2402 if (!hasNonNormalLayers &&
2403 node->compositeOpId() != COMPOSITE_OVER) {
2404
2405 hasNonNormalLayers = true;
2406 }
2407 });
2408
2409 return numLayers == 1 || (!hasNonNormalLayers && !hasTransparentLayer);
2410 }
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 1576 of file kis_layer_utils.cpp.

1577 {
1578 KisNodeList nodeParents;
1579
1580 KisNodeSP parent = node->parent();
1581 while (parent) {
1582 nodeParents << parent;
1583 parent = parent->parent();
1584 }
1585
1586 foreach(KisNodeSP perspectiveParent, parents) {
1587 if (nodeParents.contains(perspectiveParent)) {
1588 return true;
1589 }
1590 }
1591
1592 return false;
1593 }
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 1595 of file kis_layer_utils.cpp.

1596 {
1597 bool result = false;
1598
1599 KisCloneLayer *clone = dynamic_cast<KisCloneLayer*>(node.data());
1600 if (clone) {
1601 KisNodeSP cloneSource = KisNodeSP(clone->copyFrom());
1602
1603 Q_FOREACH(KisNodeSP subtree, nodes) {
1604 result =
1605 recursiveFindNode(subtree,
1606 [cloneSource](KisNodeSP node) -> bool
1607 {
1608 return node == cloneSource;
1609 });
1610
1611 if (!result) {
1612 result = checkIsCloneOf(cloneSource, nodes);
1613 }
1614
1615 if (result) {
1616 break;
1617 }
1618 }
1619 }
1620
1621 return result;
1622 }
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 2437 of file kis_layer_utils.cpp.

2438 {
2439 //Initialize all operation dependencies.
2440 ConvertToPaintLayerInfoSP info( new ConvertToPaintLayerInfo(image, src) );
2441
2442 if (!info->hasTargetNode())
2444
2445 KisImageSignalVector emitSignals;
2446 KisProcessingApplicator applicator(image, 0, KisProcessingApplicator::NONE, emitSignals, kundo2_i18n("Convert to a Paint Layer"));
2447
2448 applicator.applyCommand(new SimpleAddNode(info->image(), info->targetNode(), info->insertionParent(), info->insertionPutAfter()), KisStrokeJobData::BARRIER);
2449
2450 if (info->frames().count() > 0) {
2451 Q_FOREACH(const int& frame, info->frames()) {
2452 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, false, info->storage));
2453 applicator.applyCommand(new RefreshDelayedUpdateLayers(info->sourceNodes()), KisStrokeJobData::BARRIER);
2454 applicator.applyCommand(new RefreshHiddenAreas(info->image(), info->sourceNode()), KisStrokeJobData::BARRIER);
2455 applicator.applyCommand(new AddNewFrame(info->targetNode(), frame, info->sourceNode()), KisStrokeJobData::BARRIER);
2456 applicator.applyCommand(new UploadProjectionToFrameCommand(info->sourceNode(), info->targetNode(), frame));
2457 applicator.applyCommand(new SwitchFrameCommand(info->image(), frame, true, info->storage));
2458 }
2459 }
2460
2461 applicator.applyCommand(new SimpleRemoveLayers(info->toRemove(), info->image()));
2462
2463 applicator.end();
2464
2465 return kismpl::then(applicator.successfullyCompletedFuture(),
2466 [node = info->targetNode()] (std::future<bool> completed) {
2467 return completed.get() ? node : KisNodeSP();
2468 });
2469 }
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 2473 of file kis_layer_utils.cpp.

2474 {
2476 KisPaintDeviceSP paintDevice = node->paintDevice();
2477 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2478
2479 if (!paintDevice->keyframeChannel()) {
2480 return -1;
2481 }
2482
2483 const int activeTime = paintDevice->keyframeChannel()->activeKeyframeTime();
2484 KisRasterKeyframeSP keyframe = paintDevice->keyframeChannel()->activeKeyframeAt<KisRasterKeyframe>(activeTime);
2486
2487 return keyframe->frameID();
2488 }
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 2503 of file kis_layer_utils.cpp.

2504 {
2506 KisPaintDeviceSP paintDevice = node->paintDevice();
2508 if (!paintDevice->keyframeChannel()) {
2509 return KisTimeSpan::infinite(0);
2510 }
2511
2512 return paintDevice->keyframeChannel()->affectedFrames(time);
2513 }
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 2490 of file kis_layer_utils.cpp.

2491 {
2493 KisPaintDeviceSP paintDevice = node->paintDevice();
2494 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, -1);
2495
2496 if (!paintDevice->keyframeChannel()) {
2497 return -1;
2498 }
2499
2500 return paintDevice->keyframeChannel()->activeKeyframeTime();
2501 }

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 1375 of file kis_layer_utils.cpp.

1375 {
1376 QSet<int> frames;
1377 Q_FOREACH(KisKeyframeChannel *channel, node->keyframeChannels()) {
1378 if (!channel) {
1379 continue;
1380 }
1381
1382 KisRasterKeyframeChannel *rasterChan = dynamic_cast<KisRasterKeyframeChannel*>(channel);
1383 if (rasterChan) {
1384 frames.unite(rasterChan->allKeyframeTimes());
1385 continue;
1386 }
1387
1388 KisScalarKeyframeChannel *scalarChan = dynamic_cast<KisScalarKeyframeChannel*>(channel);
1389 if (scalarChan) {
1390 const int initialKeyframe = scalarChan->firstKeyframeTime();
1391
1392 if (initialKeyframe == -1) {
1393 continue;
1394 }
1395
1396 const int lastKeyframe = scalarChan->lastKeyframeTime();
1397 KisTimeSpan currentSpan = scalarChan->identicalFrames(initialKeyframe);
1398 while (!currentSpan.isInfinite() && currentSpan.isValid() && currentSpan.start() < lastKeyframe) {
1399 frames.insert(currentSpan.start());
1400 currentSpan = scalarChan->identicalFrames(currentSpan.end() + 1);
1401 }
1402
1403 frames.insert(lastKeyframe);
1404 }
1405
1406 }
1407
1408 return frames;
1409 }
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 1411 of file kis_layer_utils.cpp.

1411 {
1412 if (!rootNode->visible()) return QSet<int>();
1413
1414 QSet<int> frames = fetchLayerFrames(rootNode);
1415
1416 KisNodeSP node = rootNode->firstChild();
1417 while(node) {
1418 frames |= fetchLayerFramesRecursive(node);
1419 node = node->nextSibling();
1420 }
1421
1422 return frames;
1423 }
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 2515 of file kis_layer_utils.cpp.

2516 {
2517 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2518 KisPaintDeviceSP paintDevice = node->paintDevice();
2519 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2520 if (!paintDevice->keyframeChannel()) {
2521 return QSet<int>();
2522 }
2523
2524 return paintDevice->keyframeChannel()->clonesOf(node.data(), frameTime);
2525 }

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 2528 of file kis_layer_utils.cpp.

2528 {
2529 KIS_ASSERT(node);
2530 KisRasterKeyframeChannel* rasterChannel = dynamic_cast<KisRasterKeyframeChannel*>(node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false));
2531
2532 if (!rasterChannel) {
2533 return QSet<int>();
2534 }
2535
2536 return rasterChannel->timesForFrameID(frameID);
2537 }
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 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 if (!paintDevice->keyframeChannel()) {
2545 return QSet<int>();
2546 }
2547
2548 QSet<int> frameIDs;
2549
2550 Q_FOREACH( const int& frame, times ) {
2552 frameIDs << raster->frameID();
2553 }
2554
2555 return frameIDs;
2556 }

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 2570 of file kis_layer_utils.cpp.

2571 {
2572 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(node, QSet<int>());
2573 KisPaintDeviceSP paintDevice = node->paintDevice();
2574 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, QSet<int>());
2575 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice->framesInterface(), QSet<int>());
2576
2577 QSet<int> uniqueTimes;
2578
2579 Q_FOREACH( const int& id, frameIDs) {
2580 QSet<int> times = fetchLayerRasterFrameTimesMatchingID(node, id);
2581 if (times.count() > 0) {
2582 uniqueTimes.insert(*times.begin());
2583 }
2584 }
2585
2586 return uniqueTimes;
2587 }
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 2589 of file kis_layer_utils.cpp.

2590 {
2591 if (selectedTimes.isEmpty() || !node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id()))
2592 return selectedTimes;
2593
2594 // Convert a set of selected keyframe times into set of selected "frameIDs"...
2595 QSet<int> selectedFrameIDs = KisLayerUtils::fetchLayerRasterIDsAtTimes(node, selectedTimes);
2596
2597 if (filterActiveFrameID) {
2598 // Current frame was already filtered e.g. during filter preview in `KisFilterManager::apply`...
2599 // So let's remove it...
2600 const int currentActiveFrameID = KisLayerUtils::fetchLayerActiveRasterFrameID(node);
2601 selectedFrameIDs.remove(currentActiveFrameID);
2602 }
2603
2604 // Convert frameIDs to any arbitrary frame time associated with the frameID...
2605 QSet<int> uniqueFrameTimes = node->paintDevice()->framesInterface() ? KisLayerUtils::fetchLayerUniqueRasterTimesMatchingIDs(node, selectedFrameIDs) : QSet<int>();
2606
2607 return uniqueFrameTimes;
2608 }
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 1769 of file kis_layer_utils.cpp.

1770 {
1771 KIS_ASSERT_RECOVER(invisibleNodes) { return nodes; }
1772 KIS_ASSERT_RECOVER(putAfter) { return nodes; }
1773
1774 KisNodeList visibleNodes;
1775 int putAfterIndex = -1;
1776
1777 Q_FOREACH(KisNodeSP node, nodes) {
1778 if (node->visible()) {
1779 visibleNodes << node;
1780 } else if (node->userLocked()) {
1785 } else {
1786 *invisibleNodes << node;
1787
1788 if (node == *putAfter) {
1789 putAfterIndex = visibleNodes.size() - 1;
1790 }
1791 }
1792 }
1793
1794 if (!visibleNodes.isEmpty() && putAfterIndex >= 0) {
1795 putAfterIndex = qBound(0, putAfterIndex, visibleNodes.size() - 1);
1796 *putAfter = visibleNodes[putAfterIndex];
1797 }
1798
1799 return visibleNodes;
1800 }
#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 1624 of file kis_layer_utils.cpp.

1625 {
1626 KisNodeList::iterator it = nodes.begin();
1627
1628 while (it != nodes.end()) {
1629 if ((!allowMasks && !qobject_cast<KisLayer*>(it->data())) ||
1630 checkIsChildOf(*it, nodes)) {
1631 //qDebug() << "Skipping node" << ppVar((*it)->name());
1632 it = nodes.erase(it);
1633 } else {
1634 ++it;
1635 }
1636 }
1637 }
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 2558 of file kis_layer_utils.cpp.

2559 {
2561 KisPaintDeviceSP paintDevice = node->paintDevice();
2562 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(paintDevice, times);
2563 if (!paintDevice->keyframeChannel()) {
2564 return times;
2565 }
2566
2567 return paintDevice->keyframeChannel()->allKeyframeTimes().intersect(times);
2568 }

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 1802 of file kis_layer_utils.cpp.

1803 {
1804 KisNodeList::iterator it = nodes.begin();
1805
1806 while (it != nodes.end()) {
1807 if ((*it)->userLocked()) {
1808 it = nodes.erase(it);
1809 } else {
1810 ++it;
1811 }
1812 }
1813 }

◆ findImageByHierarchy()

KRITAIMAGE_EXPORT KisImageSP KisLayerUtils::findImageByHierarchy ( KisNodeSP node)

Definition at line 2302 of file kis_layer_utils.cpp.

2303 {
2304 while (node) {
2305 const KisLayer *layer = dynamic_cast<const KisLayer*>(node.data());
2306 if (layer) {
2307 return layer->image();
2308 }
2309
2310 node = node->parent();
2311 }
2312
2313 return 0;
2314 }
KisImageWSP image

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

◆ findIsolationRoot()

KRITAIMAGE_EXPORT KisNodeSP KisLayerUtils::findIsolationRoot ( KisNodeSP node)

Definition at line 2259 of file kis_layer_utils.cpp.

2260 {
2261 KisImageSP image = node->image();
2262 if (image)
2263 return image->isolationRootNode();
2264 return nullptr;
2265 }
KisNodeSP isolationRootNode() const

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

◆ findNodeByName()

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

Definition at line 2251 of file kis_layer_utils.cpp.

2252 {
2253 return recursiveFindNode(root,
2254 [name] (KisNodeSP node) {
2255 return node->name() == name;
2256 });
2257 }

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 2225 of file kis_layer_utils.cpp.

2226 {
2227 return recursiveFindNode(root,
2228 [uuid] (KisNodeSP node) {
2229 return node->uuid() == uuid;
2230 });
2231 }
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 2233 of file kis_layer_utils.cpp.

2234 {
2235 KisNodeList nodeList;
2236 KisNodeSP child = root->firstChild();
2237
2238 while (child) {
2239 if (name.isEmpty() || (!partialMatch && child->name() == name) || (partialMatch && child->name().contains(name, Qt::CaseInsensitive))) {
2240 nodeList << child;
2241 }
2242 if (recursive && child->childCount() > 0) {
2243 nodeList << findNodesByName(child, name, recursive, partialMatch);
2244 }
2245 child = child->nextSibling();
2246 }
2247
2248 return nodeList;
2249 }
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 1752 of file kis_layer_utils.cpp.

1753 {
1754 KisNodeList nodes;
1755
1756 if ((!excludeRoot || root->parent()) && root->check(props)) {
1757 nodes << root;
1758 }
1759
1760 KisNodeSP node = root->firstChild();
1761 while (node) {
1762 nodes += findNodesWithProps(node, props, excludeRoot);
1763 node = node->nextSibling();
1764 }
1765
1766 return nodes;
1767 }
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 2370 of file kis_layer_utils.cpp.

2371 {
2372 if (!node) return node;
2373
2374 while (node->parent()) {
2375 node = node->parent();
2376 }
2377 return node;
2378 }

References KisNode::parent.

◆ flattenImage()

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

Definition at line 2175 of file kis_layer_utils.cpp.

2176 {
2177 if (!activeNode) {
2178 activeNode = image->root()->lastChild();
2179 }
2180
2181
2182 KisNodeList mergedNodes;
2183 mergedNodes << image->root();
2184
2185 mergeMultipleLayersImpl(image, mergedNodes, activeNode,
2186 true, kundo2_i18n("Flatten Image"),
2187 true, QString(),
2188 flags);
2189 }
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 2161 of file kis_layer_utils.cpp.

2162 {
2163 if (!layer->childCount() && !layer->layerStyle())
2164 return;
2165
2166 KisNodeList mergedNodes;
2167 mergedNodes << layer;
2168
2169 mergeMultipleLayersImpl(image, mergedNodes, layer,
2170 true, kundo2_i18n("Flatten Layer"),
2171 true, QString(),
2172 flags);
2173 }
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 2267 of file kis_layer_utils.cpp.

2268 {
2270 [] (KisNodeSP node) {
2271 KisDelayedUpdateNodeInterface *delayedUpdate =
2272 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2273 if (delayedUpdate) {
2274 delayedUpdate->forceUpdateTimedNode();
2275 }
2276 });
2277 }
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 2290 of file kis_layer_utils.cpp.

2291 {
2293 [] (KisNodeSP node) {
2294 KisCroppedOriginalLayerInterface *croppedUpdate =
2295 dynamic_cast<KisCroppedOriginalLayerInterface*>(node.data());
2296 if (croppedUpdate) {
2297 croppedUpdate->forceUpdateHiddenAreaOnOriginal();
2298 }
2299 });
2300 }
virtual void forceUpdateHiddenAreaOnOriginal()=0

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

◆ hasDelayedNodeWithUpdates()

KRITAIMAGE_EXPORT bool KisLayerUtils::hasDelayedNodeWithUpdates ( KisNodeSP root)

Definition at line 2279 of file kis_layer_utils.cpp.

2280 {
2281 return recursiveFindNode(root,
2282 [] (KisNodeSP node) {
2283 KisDelayedUpdateNodeInterface *delayedUpdate =
2284 dynamic_cast<KisDelayedUpdateNodeInterface*>(node.data());
2285
2286 return delayedUpdate ? delayedUpdate->hasPendingTimedUpdates() : false;
2287 });
2288 }
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 1451 of file kis_layer_utils.cpp.

1452 {
1453 if (!layer->prevSibling()) return;
1454
1455 // XXX: this breaks if we allow free mixing of masks and layers
1456 KisLayerSP prevLayer = qobject_cast<KisLayer*>(layer->prevSibling().data());
1457
1458 while (prevLayer && prevLayer->isFakeNode()) {
1459 prevLayer = qobject_cast<KisLayer*>(prevLayer->prevSibling().data());
1460 }
1461
1462 if (!prevLayer) return;
1463
1464 if (!layer->visible() && !prevLayer->visible()) {
1465 return;
1466 }
1467
1468 KisImageSignalVector emitSignals;
1469 KisProcessingApplicator applicator(image, 0,
1471 emitSignals,
1472 kundo2_i18n("Merge Down"));
1473
1474 if (layer->visible() && prevLayer->visible()) {
1475 MergeDownInfoSP info(new MergeDownInfo(image, prevLayer, layer, flags));
1476
1477 // disable key strokes on all colorize masks, all onion skins on
1478 // paint layers and wait until update is finished with a barrier
1479 applicator.applyCommand(new DisableColorizeKeyStrokes(info));
1480 applicator.applyCommand(new DisableOnionSkins(info));
1481 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1482
1483 applicator.applyCommand(new KeepMergedNodesSelected(info, false));
1484 applicator.applyCommand(new FillSelectionMasks(info));
1485 applicator.applyCommand(new CreateMergedLayer(info), KisStrokeJobData::BARRIER);
1486
1487 // NOTE: shape layer may have emitted spontaneous jobs during layer creation,
1488 // wait for them to complete!
1489 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1490 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1491
1492 // in two-layer mode we disable pass through only when the destination layer
1493 // is not a group layer
1494 applicator.applyCommand(new DisablePassThroughForHeadsOnly(info, true));
1495 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1496
1497 if (info->frames.size() > 0) {
1502 const int currentTimeOnStart = info->image->animationInterface()->currentTime();
1503
1504 foreach (int frame, info->frames) {
1505 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
1506
1507 applicator.applyCommand(new AddNewFrame(info, frame));
1514 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
1515 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1516
1525 const bool skipMergingSourceLayer = !layer->isAnimated() &&
1526 frame != currentTimeOnStart;
1527
1528 applicator.applyCommand(new MergeLayers(info, skipMergingSourceLayer), KisStrokeJobData::BARRIER);
1529
1530 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage), KisStrokeJobData::BARRIER);
1531 }
1532 } else {
1533 applicator.applyCommand(new RefreshHiddenAreas(info));
1534 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
1535 applicator.applyCommand(new MergeLayers(info, false), KisStrokeJobData::BARRIER);
1536 }
1537
1538 applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
1539 applicator.applyCommand(new CleanUpNodes(info, layer),
1542 applicator.applyCommand(new KeepMergedNodesSelected(info, true));
1543 } else if (layer->visible()) {
1544 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1545 layer, KisNodeSP(),
1546 image, false));
1547
1548 applicator.applyCommand(
1549 new SimpleRemoveLayers(KisNodeList() << prevLayer,
1550 image),
1553
1554 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1555 KisNodeSP(), layer,
1556 image, true));
1557 } else if (prevLayer->visible()) {
1558 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1559 layer, KisNodeSP(),
1560 image, false));
1561
1562 applicator.applyCommand(
1563 new SimpleRemoveLayers(KisNodeList() << layer,
1564 image),
1567
1568 applicator.applyCommand(new KeepNodesSelectedCommand(KisNodeList(), KisNodeList(),
1569 KisNodeSP(), prevLayer,
1570 image, true));
1571 }
1572
1573 applicator.end();
1574 }
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 2045 of file kis_layer_utils.cpp.

2046 {
2047 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2048 false, kundo2_i18n("Merge Selected Nodes"),
2049 true, QString(),
2050 flags);
2051 }

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 1902 of file kis_layer_utils.cpp.

1906 {
1907 if (!putAfter) {
1908 putAfter = mergedNodes.first();
1909 }
1910
1911 filterMergeableNodes(mergedNodes);
1912 {
1913 KisNodeList tempNodes;
1914 std::swap(mergedNodes, tempNodes);
1915 sortMergeableNodes(image->root(), tempNodes, mergedNodes);
1916 }
1917
1918 if (mergedNodes.size() <= 1 &&
1919 (!flattenSingleLayer && mergedNodes.size() == 1)) return;
1920
1921 KisImageSignalVector emitSignals;
1922 emitSignals << ComplexNodeReselectionSignal(KisNodeSP(), KisNodeList(), KisNodeSP(), mergedNodes);
1923
1924
1925
1926 KisNodeList originalNodes = mergedNodes;
1927 KisNodeList invisibleNodes;
1928 mergedNodes = filterInvisibleNodes(originalNodes, &invisibleNodes, &putAfter);
1929
1930 if (mergedNodes.isEmpty()) return;
1931
1932
1933 // make sure we don't add the new layer into a locked group
1935 while (putAfter->parent() && !putAfter->parent()->isEditable()) {
1936 putAfter = putAfter->parent();
1937 }
1938
1946 if (!putAfter->parent()) {
1947 return;
1948 }
1949
1950 KisProcessingApplicator applicator(image, 0,
1952 emitSignals,
1953 actionName);
1954
1955
1956 if (!invisibleNodes.isEmpty() && cleanupNodes) {
1957
1958 /* If the putAfter node is invisible,
1959 * we should instead pick one of the nodes
1960 * to be merged to avoid a null putAfter
1961 * after we remove all invisible layers from
1962 * the image.
1963 * (The assumption is that putAfter is among
1964 * the layers to merge, so if it's invisible,
1965 * it's going to be removed)
1966 */
1967 if (!putAfter->visible()){
1968 putAfter = mergedNodes.first();
1969 }
1970
1971 applicator.applyCommand(
1972 new SimpleRemoveLayers(invisibleNodes,
1973 image),
1976 }
1977
1978 if (mergedNodes.size() > 1 || invisibleNodes.isEmpty()) {
1979 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, flags));
1980
1981 // disable key strokes on all colorize masks, all onion skins on
1982 // paint layers and wait until update is finished with a barrier
1983 //
1984 // when doing "new layer from visible" we should undo these changes
1985 // before the action stops, because the source layers are **not**
1986 // removed as a result of this action
1987 applicator.applyCommand(
1988 new EphemeralCommandsWrapper(info,
1989 {
1990 new DisableColorizeKeyStrokes(info),
1991 new DisableOnionSkins(info),
1992 new DisablePassThroughForHeadsOnly(info)
1993 },
1994 cleanupNodes));
1995 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
1996
1997 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, false));
1998 applicator.applyCommand(new FillSelectionMasks(info));
1999 applicator.applyCommand(new CreateMergedLayerMultiple(info, layerName), KisStrokeJobData::BARRIER);
2000 applicator.applyCommand(new EphemeralCommandsWrapper(info, { new DisableExtraCompositing(info) } , cleanupNodes));
2001 applicator.applyCommand(new KUndo2Command(), KisStrokeJobData::BARRIER);
2002
2003 if (!info->frames.isEmpty()) {
2004 foreach (int frame, info->frames) {
2005 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
2006
2007 applicator.applyCommand(new AddNewFrame(info, frame));
2014 applicator.applyCommand(new RefreshHiddenAreas(info, RefreshHiddenAreas::refresh_entire_image));
2015 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
2016 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
2017
2018 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
2019 }
2020 } else {
2021 applicator.applyCommand(new RefreshHiddenAreas(info));
2022 applicator.applyCommand(new RefreshDelayedUpdateLayers(info), KisStrokeJobData::BARRIER);
2023 applicator.applyCommand(new MergeLayersMultiple(info), KisStrokeJobData::BARRIER);
2024 }
2025
2026 //applicator.applyCommand(new MergeMetaData(info, strategy), KisStrokeJobData::BARRIER);
2027 if (cleanupNodes){
2028 applicator.applyCommand(new CleanUpNodes(info, putAfter, flattenSingleLayer),
2031 } else {
2032 applicator.applyCommand(new UndoEphemeralCommands(info));
2033 applicator.applyCommand(new InsertNode(info, putAfter),
2036 }
2037
2038 applicator.applyCommand(new KeepMergedNodesSelected(info, putAfter, true));
2039 }
2040
2041 applicator.end();
2042
2043 }
#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 2053 of file kis_layer_utils.cpp.

2054 {
2055 if (!tryMergeSelectionMasks(image, mergedNodes, putAfter)) {
2056 mergeMultipleLayers(image, mergedNodes, putAfter, flags);
2057 }
2058 }
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 2060 of file kis_layer_utils.cpp.

2061 {
2062 KisNodeList mergedNodes;
2063 mergedNodes << image->root();
2064
2065 mergeMultipleLayersImpl(image, mergedNodes, putAfter,
2066 true, kundo2_i18n("New From Visible"),
2067 false, i18nc("New layer created from all the visible layers", "Visible"),
2068 flags);
2069 }

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 2207 of file kis_layer_utils.cpp.

2208 {
2209 if (func(node)) {
2210 return node;
2211 }
2212
2213 node = node->firstChild();
2214 while (node) {
2215 KisNodeSP resultNode = recursiveFindNode(node, func);
2216 if (resultNode) {
2217 return resultNode;
2218 }
2219 node = node->nextSibling();
2220 }
2221
2222 return 0;
2223 }

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

◆ recursiveTightNodeVisibleBounds()

KRITAIMAGE_EXPORT QRect KisLayerUtils::recursiveTightNodeVisibleBounds ( KisNodeSP rootNode)

Definition at line 2361 of file kis_layer_utils.cpp.

2362 {
2363 QRect exactBounds;
2364 recursiveApplyNodes(rootNode, [&exactBounds] (KisNodeSP node) {
2365 exactBounds |= node->projectionPlane()->tightUserVisibleBounds();
2366 });
2367 return exactBounds;
2368 }
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 2357 of file kis_layer_utils.cpp.

2357 {
2358 Private::refreshHiddenAreaAsync(image, rootNode, preparedArea, QRect());
2359 }

References KisLayerUtils::Private::refreshHiddenAreaAsync().

◆ sortAndFilterAnyMergeableNodesSafe()

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

Definition at line 1716 of file kis_layer_utils.cpp.

1716 {
1717 KisNodeList filteredNodes = nodes;
1718 KisNodeList sortedNodes;
1719
1720 KisLayerUtils::filterMergeableNodes(filteredNodes, true);
1721
1722 bool haveExternalNodes = false;
1723 Q_FOREACH (KisNodeSP node, nodes) {
1724 if (node->graphListener() != image->root()->graphListener()) {
1725 haveExternalNodes = true;
1726 break;
1727 }
1728 }
1729
1730 if (!haveExternalNodes) {
1731 KisLayerUtils::sortMergeableNodes(image->root(), filteredNodes, sortedNodes);
1732 } else {
1733 sortedNodes = filteredNodes;
1734 }
1735
1736 return sortedNodes;
1737 }
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 1671 of file kis_layer_utils.cpp.

1672 {
1673 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1674
1675 KisNodeSP root;
1676 Q_FOREACH(KisNodeSP node, nodes) {
1677 KisNodeSP localRoot = node;
1678 while (localRoot->parent()) {
1679 localRoot = localRoot->parent();
1680 }
1681
1682 if (!root) {
1683 root = localRoot;
1684 }
1685 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1686 }
1687
1688 KisNodeList result;
1689 sortMergeableNodes(root, nodes, result);
1690 filterMergeableNodes(result, allowMasks);
1691 return result;
1692 }
#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 1694 of file kis_layer_utils.cpp.

1695 {
1696 KIS_SAFE_ASSERT_RECOVER(!nodes.isEmpty()) { return nodes; }
1697
1698 KisNodeSP root;
1699 Q_FOREACH(KisNodeSP node, nodes) {
1700 KisNodeSP localRoot = node;
1701 while (localRoot->parent()) {
1702 localRoot = localRoot->parent();
1703 }
1704
1705 if (!root) {
1706 root = localRoot;
1707 }
1708 KIS_SAFE_ASSERT_RECOVER(root == localRoot) { return nodes; }
1709 }
1710
1711 KisNodeList result;
1712 sortMergeableNodes(root, nodes, result);
1713 return result;
1714 }

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 1639 of file kis_layer_utils.cpp.

1640 {
1641 KisNodeList::iterator it = std::find(inputNodes.begin(), inputNodes.end(), root);
1642
1643 if (it != inputNodes.end()) {
1644 outputNodes << *it;
1645 inputNodes.erase(it);
1646 }
1647
1648 if (inputNodes.isEmpty()) {
1649 return;
1650 }
1651
1652 KisNodeSP child = root->firstChild();
1653 while (child) {
1654 sortMergeableNodes(child, inputNodes, outputNodes);
1655 child = child->nextSibling();
1656 }
1657
1661 KIS_ASSERT_RECOVER_NOOP(root->parent() || inputNodes.isEmpty());
1662 }
#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 1664 of file kis_layer_utils.cpp.

1665 {
1666 KisNodeList result;
1667 sortMergeableNodes(root, nodes, result);
1668 return result;
1669 }

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 2412 of file kis_layer_utils.cpp.

2413 {
2414 SplitAlphaToMaskInfoSP info( new SplitAlphaToMaskInfo(node->image(), node, maskName) );
2415
2416 KisImageSignalVector emitSignals;
2417 KisProcessingApplicator applicator(image, 0,
2419 emitSignals,
2420 kundo2_i18n("Split Alpha into a Mask"));
2421
2422 applicator.applyCommand(new SimpleAddNode(info->image, info->getMask(), info->node), KisStrokeJobData::BARRIER);
2423 applicator.applyCommand(new InitSplitAlphaSelectionMask(info));
2424 if (info->frames.count() > 0) {
2425 Q_FOREACH(const int& frame, info->frames) {
2426 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, false, info->storage));
2427 applicator.applyCommand(new AddNewFrame(info->getMask(), frame, info->node));
2428 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2429 applicator.applyCommand(new SwitchFrameCommand(info->image, frame, true, info->storage));
2430 }
2431 } else {
2432 applicator.applyCommand(new SplitAlphaCommand(info), KisStrokeJobData::BARRIER);
2433 }
2434 applicator.end();
2435 }

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 1142 of file kis_layer_utils.cpp.

1143 {
1144 QSet<KisNodeSP> nodesToHide;
1145 QSet<KisNodeSP> extraNodesToRemove;
1146
1147 for (auto it = nodesToRemove.begin(); it != nodesToRemove.end(); ++it) {
1148 KisNodeSP root = *it;
1150
1151 if (!root->isEditable(false)) {
1152 nodesToHide.insert(root);
1153 } else {
1154 bool rootNeedsCarefulRemoval = false;
1155
1156 recursiveApplyNodes(root,
1157 [root, &nodesToHide, &rootNeedsCarefulRemoval] (KisNodeSP node) {
1158 if (!node->isEditable(false)) {
1159 while (node != root) {
1160 nodesToHide.insert(node);
1161 node = node->parent();
1162 KIS_SAFE_ASSERT_RECOVER_BREAK(node);
1163 }
1164 nodesToHide.insert(root);
1165 rootNeedsCarefulRemoval = true;
1166 }
1167 });
1168
1169 if (rootNeedsCarefulRemoval) {
1171 [&extraNodesToRemove] (KisNodeSP node) {
1172 extraNodesToRemove.insert(node);
1173 });
1174 }
1175 }
1176 }
1177 nodesToRemove += KisNodeList(extraNodesToRemove.begin(), extraNodesToRemove.end());
1178 KritaUtils::filterContainer<KisNodeList>(nodesToRemove,
1179 [nodesToHide](KisNodeSP node) {
1180 return !nodesToHide.contains(node);
1181 });
1182 _nodesToHide = KisNodeList(nodesToHide.begin(), nodesToHide.end());
1183 }
#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 2122 of file kis_layer_utils.cpp.

2123 {
2124 QList<KisSelectionMaskSP> selectionMasks;
2125
2126 for (auto it = mergedNodes.begin(); it != mergedNodes.end(); /*noop*/) {
2127 KisSelectionMaskSP mask = dynamic_cast<KisSelectionMask*>(it->data());
2128 if (!mask) {
2129 it = mergedNodes.erase(it);
2130 } else {
2131 selectionMasks.append(mask);
2132 ++it;
2133 }
2134 }
2135
2136 if (mergedNodes.isEmpty()) return false;
2137
2138 KisLayerSP parentLayer = qobject_cast<KisLayer*>(selectionMasks.first()->parent().data());
2139 KIS_ASSERT_RECOVER(parentLayer) { return 0; }
2140
2141 KisImageSignalVector emitSignals;
2142
2143 KisProcessingApplicator applicator(image, 0,
2145 emitSignals,
2146 kundo2_i18n("Merge Selection Masks"));
2147
2148 MergeMultipleInfoSP info(new MergeMultipleInfo(image, mergedNodes, None));
2149
2150
2151 applicator.applyCommand(new MergeSelectionMasks(info, putAfter));
2152 applicator.applyCommand(new CleanUpNodes(info, putAfter),
2155 applicator.applyCommand(new ActivateSelectionMask(info));
2156 applicator.end();
2157
2158 return true;
2159 }

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 1425 of file kis_layer_utils.cpp.

1425 {
1426 QSet<int> frames = fetchLayerFrames(node);
1427 frames = fetchUniqueFrameTimes(node, frames, false);
1428
1429 if (frames.isEmpty()) {
1430 (*jobs)[0].insert(node);
1431 } else {
1432 foreach (int frame, frames) {
1433 (*jobs)[frame].insert(node);
1434 }
1435 }
1436 }
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 1438 of file kis_layer_utils.cpp.

1438 {
1439 updateFrameJobs(jobs, rootNode);
1440
1441 KisNodeSP node = rootNode->firstChild();
1442 while(node) {
1443 updateFrameJobsRecursive(jobs, node);
1444 node = node->nextSibling();
1445 }
1446 }
void updateFrameJobs(FrameJobs *jobs, KisNodeSP node)
void updateFrameJobsRecursive(FrameJobs *jobs, KisNodeSP rootNode)

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