diff --git a/libs/image/kis_properties_configuration.cc b/libs/image/kis_properties_configuration.cc index 1f60cf3d25..03bf545626 100644 --- a/libs/image/kis_properties_configuration.cc +++ b/libs/image/kis_properties_configuration.cc @@ -1,465 +1,465 @@ /* * Copyright (c) 2006 Boudewijn Rempt * Copyright (c) 2007,2010 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_properties_configuration.h" #include #include #include #include "kis_image.h" #include "kis_transaction.h" #include "kis_undo_adapter.h" #include "kis_painter.h" #include "kis_selection.h" #include "KoID.h" #include "kis_types.h" #include #include #include struct Q_DECL_HIDDEN KisPropertiesConfiguration::Private { QMap properties; QStringList notSavedProperties; }; KisPropertiesConfiguration::KisPropertiesConfiguration() : d(new Private) { } KisPropertiesConfiguration::~KisPropertiesConfiguration() { delete d; } KisPropertiesConfiguration::KisPropertiesConfiguration(const KisPropertiesConfiguration& rhs) : KisSerializableConfiguration(rhs) , d(new Private(*rhs.d)) { } KisPropertiesConfiguration &KisPropertiesConfiguration::operator=(const KisPropertiesConfiguration &rhs) { if (&rhs != this) { *d = *rhs.d; } return *this; } bool KisPropertiesConfiguration::fromXML(const QString & xml, bool clear) { if (clear) { clearProperties(); } QDomDocument doc; bool retval = doc.setContent(xml); if (retval) { QDomElement e = doc.documentElement(); fromXML(e); } return retval; } void KisPropertiesConfiguration::fromXML(const QDomElement& e) { QDomNode n = e.firstChild(); while (!n.isNull()) { // We don't nest elements in filter configuration. For now... QDomElement e = n.toElement(); if (!e.isNull()) { if (e.tagName() == "param") { // If the file contains the new type parameter introduced in Krita act on it // Else invoke old behaviour if(e.attributes().contains("type")) { QString type = e.attribute("type"); QString name = e.attribute("name"); QString value = e.text(); if (type == "bytearray") { d->properties[name] = QVariant(QByteArray::fromBase64(value.toLatin1())); } else { d->properties[name] = value; } } else { d->properties[e.attribute("name")] = QVariant(e.text()); } } } n = n.nextSibling(); } //dump(); } void KisPropertiesConfiguration::toXML(QDomDocument& doc, QDomElement& root) const { QMap::Iterator it; for (it = d->properties.begin(); it != d->properties.end(); ++it) { if(d->notSavedProperties.contains(it.key())) { continue; } QDomElement e = doc.createElement("param"); e.setAttribute("name", QString(it.key().toLatin1())); QString type = "string"; QVariant v = it.value(); QDomText text; if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { text = doc.createCDATASection(v.value().toString()); } else if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { QDomDocument cdataDoc = QDomDocument("color"); QDomElement cdataRoot = cdataDoc.createElement("color"); cdataDoc.appendChild(cdataRoot); v.value().toXML(cdataDoc, cdataRoot); text = cdataDoc.createCDATASection(cdataDoc.toString()); type = "color"; } else if(v.type() == QVariant::String ) { text = doc.createCDATASection(v.toString()); // XXX: Unittest this! type = "string"; } else if(v.type() == QVariant::ByteArray ) { text = doc.createTextNode(QString::fromLatin1(v.toByteArray().toBase64())); // Arbitrary Data type = "bytearray"; } else { text = doc.createTextNode(v.toString()); type = "internal"; } e.setAttribute("type", type); e.appendChild(text); root.appendChild(e); } } QString KisPropertiesConfiguration::toXML() const { QDomDocument doc = QDomDocument("params"); QDomElement root = doc.createElement("params"); doc.appendChild(root); toXML(doc, root); return doc.toString(); } bool KisPropertiesConfiguration::hasProperty(const QString& name) const { return d->properties.contains(name); } void KisPropertiesConfiguration::setProperty(const QString & name, const QVariant & value) { if (d->properties.find(name) == d->properties.end()) { d->properties.insert(name, value); } else { d->properties[name] = value; } } bool KisPropertiesConfiguration::getProperty(const QString & name, QVariant & value) const { if (d->properties.find(name) == d->properties.end()) { return false; } else { value = d->properties[name]; return true; } } QVariant KisPropertiesConfiguration::getProperty(const QString & name) const { if (d->properties.find(name) == d->properties.end()) { return QVariant(); } else { return d->properties[name]; } } int KisPropertiesConfiguration::getInt(const QString & name, int def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toInt(); else return def; } double KisPropertiesConfiguration::getDouble(const QString & name, double def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toDouble(); else return def; } float KisPropertiesConfiguration::getFloat(const QString & name, float def) const { QVariant v = getProperty(name); if (v.isValid()) return (float)v.toDouble(); else return def; } bool KisPropertiesConfiguration::getBool(const QString & name, bool def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toBool(); else return def; } QString KisPropertiesConfiguration::getString(const QString & name, const QString & def) const { QVariant v = getProperty(name); if (v.isValid()) return v.toString(); else return def; } KisCubicCurve KisPropertiesConfiguration::getCubicCurve(const QString & name, const KisCubicCurve & curve) const { QVariant v = getProperty(name); if (v.isValid()) { if (v.type() == QVariant::UserType && v.userType() == qMetaTypeId()) { return v.value(); } else { KisCubicCurve c; c.fromString(v.toString()); return c; } } else return curve; } KoColor KisPropertiesConfiguration::getColor(const QString& name, const KoColor& color) const { QVariant v = getProperty(name); if (v.isValid()) { switch(v.type()) { case QVariant::UserType: { if (v.userType() == qMetaTypeId()) { return v.value(); } break; } case QVariant::String: { QDomDocument doc; if (doc.setContent(v.toString())) { QDomElement e = doc.documentElement().firstChild().toElement(); bool ok; KoColor c = KoColor::fromXML(e, Integer16BitsColorDepthID.id(), &ok); if (ok) { return c; } } else { QColor c(v.toString()); if (c.isValid()) { KoColor kc(c, KoColorSpaceRegistry::instance()->rgb8()); return kc; } } break; } case QVariant::Color: { QColor c = v.value(); KoColor kc(c, KoColorSpaceRegistry::instance()->rgb8()); return kc; } case QVariant::Int: { QColor c(v.toInt()); if (c.isValid()) { KoColor kc(c, KoColorSpaceRegistry::instance()->rgb8()); return kc; } break; } default: ; } } return color; } void KisPropertiesConfiguration::dump() const { -// QMap::Iterator it; -// for (it = d->properties.begin(); it != d->properties.end(); ++it) { -// qDebug() << it.key() << " = " << it.value() << it.value().typeName(); -// } + QMap::Iterator it; + for (it = d->properties.begin(); it != d->properties.end(); ++it) { + qDebug() << it.key() << " = " << it.value() << it.value().typeName(); + } } void KisPropertiesConfiguration::clearProperties() { d->properties.clear(); } void KisPropertiesConfiguration::setPropertyNotSaved(const QString& name) { d->notSavedProperties.append(name); } QMap KisPropertiesConfiguration::getProperties() const { return d->properties; } void KisPropertiesConfiguration::removeProperty(const QString & name) { d->properties.remove(name); } QList KisPropertiesConfiguration::getPropertiesKeys() const { return d->properties.keys(); } void KisPropertiesConfiguration::getPrefixedProperties(const QString &prefix, KisPropertiesConfiguration *config) const { const int prefixSize = prefix.size(); const QList keys = getPropertiesKeys(); Q_FOREACH (const QString &key, keys) { if (key.startsWith(prefix)) { config->setProperty(key.mid(prefixSize), getProperty(key)); } } } void KisPropertiesConfiguration::getPrefixedProperties(const QString &prefix, KisPropertiesConfigurationSP config) const { getPrefixedProperties(prefix, config.data()); } void KisPropertiesConfiguration::setPrefixedProperties(const QString &prefix, const KisPropertiesConfiguration *config) { const QList keys = config->getPropertiesKeys(); Q_FOREACH (const QString &key, keys) { this->setProperty(prefix + key, config->getProperty(key)); } } void KisPropertiesConfiguration::setPrefixedProperties(const QString &prefix, const KisPropertiesConfigurationSP config) { setPrefixedProperties(prefix, config.data()); } QString KisPropertiesConfiguration::escapeString(const QString &string) { QString result = string; result.replace(";", "\\;"); result.replace("]", "\\]"); result.replace(">", "\\>"); return result; } QString KisPropertiesConfiguration::unescapeString(const QString &string) { QString result = string; result.replace("\\;", ";"); result.replace("\\]", "]"); result.replace("\\>", ">"); return result; } void KisPropertiesConfiguration::setProperty(const QString &name, const QStringList &value) { QStringList escapedList; escapedList.reserve(value.size()); Q_FOREACH (const QString &str, value) { escapedList << escapeString(str); } setProperty(name, escapedList.join(';')); } QStringList KisPropertiesConfiguration::getStringList(const QString &name, const QStringList &defaultValue) const { if (!hasProperty(name)) return defaultValue; const QString joined = getString(name); QStringList result; int afterLastMatch = -1; for (int i = 0; i < joined.size(); i++) { const bool lastChunk = i == joined.size() - 1; const bool matchedSplitter = joined[i] == ';' && (i == 0 || joined[i - 1] != '\\'); if (lastChunk || matchedSplitter) { result << unescapeString(joined.mid(afterLastMatch, i - afterLastMatch + int(lastChunk && !matchedSplitter))); afterLastMatch = i + 1; } if (lastChunk && matchedSplitter) { result << QString(); } } return result; } QStringList KisPropertiesConfiguration::getPropertyLazy(const QString &name, const QStringList &defaultValue) const { return getStringList(name, defaultValue); } // --- factory --- struct Q_DECL_HIDDEN KisPropertiesConfigurationFactory::Private { }; KisPropertiesConfigurationFactory::KisPropertiesConfigurationFactory() : d(new Private) { } KisPropertiesConfigurationFactory::~KisPropertiesConfigurationFactory() { delete d; } KisSerializableConfigurationSP KisPropertiesConfigurationFactory::createDefault() { return new KisPropertiesConfiguration(); } KisSerializableConfigurationSP KisPropertiesConfigurationFactory::create(const QDomElement& e) { KisPropertiesConfigurationSP pc = new KisPropertiesConfiguration(); pc->fromXML(e); return pc; } diff --git a/libs/image/tiles3/KisTiledExtentManager.cpp b/libs/image/tiles3/KisTiledExtentManager.cpp index 9217fb4140..9a71e0aa05 100644 --- a/libs/image/tiles3/KisTiledExtentManager.cpp +++ b/libs/image/tiles3/KisTiledExtentManager.cpp @@ -1,153 +1,152 @@ /* * Copyright (c) 2017 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KisTiledExtentManager.h" #include #include #include "kis_tile_data_interface.h" #include "kis_assert.h" #include "kis_global.h" - namespace { inline bool addTileToMap(int index, QMap *map) { bool needsUpdateExtent = false; auto it = map->find(index); if (it == map->end()) { map->insert(index, 1); needsUpdateExtent = true; } else { KIS_ASSERT_RECOVER_NOOP(*it > 0); (*it)++; } return needsUpdateExtent; } inline bool removeTileFromMap(int index, QMap *map) { bool needsUpdateExtent = false; auto it = map->find(index); if (it == map->end()) { KIS_ASSERT_RECOVER_NOOP(0 && "sanity check failed: the tile has already been removed!"); } else { KIS_ASSERT_RECOVER_NOOP(*it > 0); (*it)--; if (*it <= 0) { map->erase(it); needsUpdateExtent = true; } } return needsUpdateExtent; } } KisTiledExtentManager::KisTiledExtentManager() { } void KisTiledExtentManager::notifyTileAdded(int col, int row) { QMutexLocker l(&m_mutex); bool needsUpdateExtent = false; needsUpdateExtent |= addTileToMap(col, &m_colMap); needsUpdateExtent |= addTileToMap(row, &m_rowMap); if (needsUpdateExtent) { updateExtent(); } } void KisTiledExtentManager::notifyTileRemoved(int col, int row) { QMutexLocker l(&m_mutex); bool needsUpdateExtent = false; needsUpdateExtent |= removeTileFromMap(col, &m_colMap); needsUpdateExtent |= removeTileFromMap(row, &m_rowMap); if (needsUpdateExtent) { updateExtent(); } } void KisTiledExtentManager::replaceTileStats(const QVector &indexes) { QMutexLocker l(&m_mutex); m_colMap.clear(); m_rowMap.clear(); Q_FOREACH (const QPoint &index, indexes) { addTileToMap(index.x(), &m_colMap); addTileToMap(index.y(), &m_rowMap); } updateExtent(); } void KisTiledExtentManager::clear() { QMutexLocker l(&m_mutex); m_colMap.clear(); m_rowMap.clear(); m_currentExtent = QRect(qint32_MAX, qint32_MAX, 0, 0); } QRect KisTiledExtentManager::extent() const { QMutexLocker l(&m_mutex); return m_currentExtent; } void KisTiledExtentManager::updateExtent() { KIS_ASSERT_RECOVER_RETURN(m_colMap.isEmpty() == m_rowMap.isEmpty()); // here we check for only one map for efficiency reasons if (m_colMap.isEmpty()) { m_currentExtent = QRect(qint32_MAX, qint32_MAX, 0, 0); } else { const int minX = m_colMap.firstKey() * KisTileData::WIDTH; const int maxPlusOneX = (m_colMap.lastKey() + 1) * KisTileData::WIDTH; const int minY = m_rowMap.firstKey() * KisTileData::HEIGHT; const int maxPlusOneY = (m_rowMap.lastKey() + 1) * KisTileData::HEIGHT; m_currentExtent = QRect(minX, minY, maxPlusOneX - minX, maxPlusOneY - minY); } } diff --git a/libs/image/tiles3/kis_tile_hash_table.h b/libs/image/tiles3/kis_tile_hash_table.h index 658b782f55..e5e25fa3e7 100644 --- a/libs/image/tiles3/kis_tile_hash_table.h +++ b/libs/image/tiles3/kis_tile_hash_table.h @@ -1,234 +1,235 @@ /* * Copyright (c) 2004 C. Boemann * (c) 2009 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TILEHASHTABLE_H_ #define KIS_TILEHASHTABLE_H_ #include "kis_tile.h" + /** * This is a template for a hash table that stores tiles (or some other * objects resembling tiles). Actually, this object should only have * col()/row() methods and be able to answer setNext()/next() requests to * be stored here. It is used in KisTiledDataManager and * KisMementoManager. */ template class KisTileHashTableTraits { public: typedef T TileType; typedef KisSharedPtr TileTypeSP; typedef KisWeakSharedPtr TileTypeWSP; KisTileHashTableTraits(KisMementoManager *mm); KisTileHashTableTraits(const KisTileHashTableTraits &ht, KisMementoManager *mm); /* virtual? */ ~KisTileHashTableTraits(); bool isEmpty() { return !m_numTiles; } bool tileExists(qint32 col, qint32 row); /** * Returns a tile in position (col,row). If no tile exists, * returns null. * \param col column of the tile * \param row row of the tile */ TileTypeSP getExistingTile(qint32 col, qint32 row); /** * Returns a tile in position (col,row). If no tile exists, * creates a new one, attaches it to the list and returns. * \param col column of the tile * \param row row of the tile * \param newTile out-parameter, returns true if a new tile * was created */ TileTypeSP getTileLazy(qint32 col, qint32 row, bool& newTile); /** * Returns a tile in position (col,row). If no tile exists, * creates nothing, but returns shared default tile object * of the table. Be careful, this object has column and row * parameters set to (qint32_MIN, qint32_MIN). * \param col column of the tile * \param row row of the tile * \param existingTile returns true if the tile actually exists in the table * and it is not a lazily created default wrapper tile */ TileTypeSP getReadOnlyTileLazy(qint32 col, qint32 row, bool &existingTile); void addTile(TileTypeSP tile); bool deleteTile(TileTypeSP tile); bool deleteTile(qint32 col, qint32 row); void clear(); void setDefaultTileData(KisTileData *defaultTileData); KisTileData* defaultTileData() const; qint32 numTiles() { return m_numTiles; } void debugPrintInfo(); void debugMaxListLength(qint32 &min, qint32 &max); private: TileTypeSP getTileMinefieldWalk(qint32 col, qint32 row, qint32 idx); TileTypeSP getTile(qint32 col, qint32 row, qint32 idx); void linkTile(TileTypeSP tile, qint32 idx); bool unlinkTile(qint32 col, qint32 row, qint32 idx); inline void setDefaultTileDataImp(KisTileData *defaultTileData); inline KisTileData* defaultTileDataImp() const; static inline quint32 calculateHash(qint32 col, qint32 row); inline qint32 debugChainLen(qint32 idx); void debugListLengthDistibution(); void sanityChecksumCheck(); private: template friend class KisTileHashTableIteratorTraits; static const qint32 TABLE_SIZE = 1024; TileTypeSP *m_hashTable; qint32 m_numTiles; KisTileData *m_defaultTileData; KisMementoManager *m_mementoManager; mutable QReadWriteLock m_lock; }; #include "kis_tile_hash_table_p.h" /** * Walks through all tiles inside hash table * Note: You can't work with your hash table in a regular way * during iterating with this iterator, because HT is locked. * The only thing you can do is to delete current tile. * * LockerType defines if the iterator is constant or mutable. One should * pass either QReadLocker or QWriteLocker as a parameter. */ template class KisTileHashTableIteratorTraits { public: typedef T TileType; typedef KisSharedPtr TileTypeSP; KisTileHashTableIteratorTraits(KisTileHashTableTraits *ht) : m_locker(&ht->m_lock) { m_hashTable = ht; m_index = nextNonEmptyList(0); if (m_index < KisTileHashTableTraits::TABLE_SIZE) m_tile = m_hashTable->m_hashTable[m_index]; } ~KisTileHashTableIteratorTraits() { } void next() { if (m_tile) { m_tile = m_tile->next(); if (!m_tile) { qint32 idx = nextNonEmptyList(m_index + 1); if (idx < KisTileHashTableTraits::TABLE_SIZE) { m_index = idx; m_tile = m_hashTable->m_hashTable[idx]; } else { //EOList reached m_index = -1; // m_tile.clear(); // already null } } } } TileTypeSP tile() const { return m_tile; } bool isDone() const { return !m_tile; } // disable the method if we didn't lock for writing template typename std::enable_if::value, void>::type deleteCurrent() { TileTypeSP tile = m_tile; next(); const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); m_hashTable->unlinkTile(tile->col(), tile->row(), idx); } // disable the method if we didn't lock for writing template typename std::enable_if::value, void>::type moveCurrentToHashTable(KisTileHashTableTraits *newHashTable) { TileTypeSP tile = m_tile; next(); const qint32 idx = m_hashTable->calculateHash(tile->col(), tile->row()); m_hashTable->unlinkTile(tile->col(), tile->row(), idx); newHashTable->addTile(tile); } protected: TileTypeSP m_tile; qint32 m_index; KisTileHashTableTraits *m_hashTable; LockerType m_locker; protected: qint32 nextNonEmptyList(qint32 startIdx) { qint32 idx = startIdx; while (idx < KisTileHashTableTraits::TABLE_SIZE && !m_hashTable->m_hashTable[idx]) { idx++; } return idx; } private: Q_DISABLE_COPY(KisTileHashTableIteratorTraits) }; typedef KisTileHashTableTraits KisTileHashTable; typedef KisTileHashTableIteratorTraits KisTileHashTableIterator; typedef KisTileHashTableIteratorTraits KisTileHashTableConstIterator; #endif /* KIS_TILEHASHTABLE_H_ */