File indexing completed on 2024-12-22 04:15:39

0001 /*
0002  *  SPDX-FileCopyrightText: 2014 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_exr_layers_sorter.h"
0008 
0009 #include <QDomDocument>
0010 #include <QDomElement>
0011 
0012 #include "kis_image.h"
0013 #include "exr_extra_tags.h"
0014 #include "kis_kra_savexml_visitor.h"
0015 #include "kis_paint_layer.h"
0016 
0017 
0018 struct KisExrLayersSorter::Private
0019 {
0020     Private(const QDomDocument &_extraData, KisImageSP _image)
0021         : extraData(_extraData), image(_image) {}
0022 
0023     const QDomDocument &extraData;
0024     KisImageSP image;
0025 
0026     QMap<QString, QDomElement> pathToElementMap;
0027     QMap<QString, int> pathToOrderingMap;
0028 
0029     QMap<KisNodeSP, int> nodeToOrderingMap;
0030 
0031     void createOrderingMap();
0032     void processLayers(KisNodeSP root);
0033     void sortLayers(KisNodeSP root);
0034 };
0035 
0036 QString getNodePath(KisNodeSP node) {
0037     KIS_ASSERT_RECOVER(node) { return "UNDEFINED"; }
0038 
0039     QString path;
0040 
0041     KisNodeSP parentNode = node->parent();
0042     while(parentNode) {
0043         if (!path.isEmpty()) {
0044             path.prepend(".");
0045         }
0046         path.prepend(node->name());
0047 
0048         node = parentNode;
0049         parentNode = node->parent();
0050     }
0051 
0052     return path;
0053 }
0054 
0055 void KisExrLayersSorter::Private::createOrderingMap()
0056 {
0057     int index = 0;
0058     QDomElement el = extraData.documentElement().firstChildElement();
0059 
0060 
0061     while (!el.isNull()) {
0062         QString path = el.attribute(EXR_NAME);
0063         pathToElementMap.insert(path, el);
0064         pathToOrderingMap.insert(path, index);
0065 
0066         el = el.nextSiblingElement();
0067         index++;
0068     }
0069 }
0070 
0071 template <typename T>
0072 T fetchMapValueLazy(const QMap<QString, T> &map, QString path)
0073 {
0074     if (map.contains(path)) return map[path];
0075 
0076 
0077     typename QMap<QString, T>::const_iterator it = map.constBegin();
0078     typename QMap<QString, T>::const_iterator end = map.constEnd();
0079 
0080     for (; it != end; ++it) {
0081         if (it.key().startsWith(path)) {
0082             return it.value();
0083         }
0084     }
0085 
0086     return T();
0087 }
0088 
0089 void KisExrLayersSorter::Private::processLayers(KisNodeSP root)
0090 {
0091     if (root && root->parent()) {
0092         QString path = getNodePath(root);
0093 
0094         nodeToOrderingMap.insert(root, fetchMapValueLazy(pathToOrderingMap, path));
0095 
0096         if (KisPaintLayer *paintLayer = dynamic_cast<KisPaintLayer*>(root.data())) {
0097             KisSaveXmlVisitor::loadPaintLayerAttributes(pathToElementMap[path], paintLayer);
0098         }
0099     }
0100 
0101     KisNodeSP child = root->firstChild();
0102     while (child) {
0103         processLayers(child);
0104         child = child->nextSibling();
0105     }
0106 }
0107 
0108 struct CompareNodesFunctor
0109 {
0110     CompareNodesFunctor(const QMap<KisNodeSP, int> &map)
0111         : m_nodeToOrderingMap(map) {}
0112 
0113     bool operator() (KisNodeSP lhs, KisNodeSP rhs) {
0114         return m_nodeToOrderingMap[lhs] < m_nodeToOrderingMap[rhs];
0115     }
0116 
0117 private:
0118     const QMap<KisNodeSP, int> &m_nodeToOrderingMap;
0119 };
0120 
0121 
0122 void KisExrLayersSorter::Private::sortLayers(KisNodeSP root)
0123 {
0124     QList<KisNodeSP> childNodes;
0125 
0126     // first move all the children to the list
0127     KisNodeSP child = root->firstChild();
0128     while (child) {
0129         KisNodeSP lastChild = child;
0130         child = child->nextSibling();
0131 
0132         childNodes.append(lastChild);
0133         image->removeNode(lastChild);
0134     }
0135 
0136     // sort the list
0137     std::stable_sort(childNodes.begin(), childNodes.end(), CompareNodesFunctor(nodeToOrderingMap));
0138 
0139     // put the children back
0140     Q_FOREACH (KisNodeSP node, childNodes) {
0141         image->addNode(node, root, root->childCount());
0142     }
0143 
0144     // recursive calls
0145     child = root->firstChild();
0146     while (child) {
0147         sortLayers(child);
0148         child = child->nextSibling();
0149     }
0150 }
0151 
0152 KisExrLayersSorter::KisExrLayersSorter(const QDomDocument &extraData, KisImageSP image)
0153     : m_d(new Private(extraData, image))
0154 {
0155     KIS_ASSERT_RECOVER_RETURN(!extraData.isNull());
0156     m_d->createOrderingMap();
0157 
0158     m_d->processLayers(image->root());
0159     m_d->sortLayers(image->root());
0160 }
0161 
0162 KisExrLayersSorter::~KisExrLayersSorter()
0163 {
0164 }