File indexing completed on 2024-05-26 04:28:04

0001 /*
0002  *  copyright (c) 2006,2010 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_random_accessor.h"
0008 
0009 
0010 #include <kis_debug.h>
0011 
0012 
0013 const quint32 KisRandomAccessor2::CACHESIZE = 4; // Define the number of tiles we keep in cache
0014 
0015 KisRandomAccessor2::KisRandomAccessor2(KisTiledDataManager *ktm, qint32 offsetX, qint32 offsetY, bool writable, KisIteratorCompleteListener *completeListener) :
0016         m_ktm(ktm),
0017         m_tilesCache(new KisTileInfo*[CACHESIZE]),
0018         m_tilesCacheSize(0),
0019         m_pixelSize(m_ktm->pixelSize()),
0020         m_data(0),
0021         m_oldData(0),
0022         m_writable(writable),
0023         m_lastX(0),
0024         m_lastY(0),
0025         m_offsetX(offsetX),
0026         m_offsetY(offsetY),
0027         m_completeListener(completeListener)
0028 {
0029     Q_ASSERT(ktm != 0);
0030 }
0031 
0032 KisRandomAccessor2::~KisRandomAccessor2()
0033 {
0034     for (uint i = 0; i < m_tilesCacheSize; i++) {
0035         unlockTile(m_tilesCache[i]->tile);
0036         unlockOldTile(m_tilesCache[i]->oldtile);
0037         delete m_tilesCache[i];
0038     }
0039     delete [] m_tilesCache;
0040 
0041     if (m_writable && m_completeListener) {
0042         m_completeListener->notifyWritableIteratorCompleted();
0043     }
0044 }
0045 
0046 void KisRandomAccessor2::moveTo(qint32 x, qint32 y)
0047 {
0048     m_lastX = x;
0049     m_lastY = y;
0050 
0051     x -= m_offsetX;
0052     y -= m_offsetY;
0053 
0054     // Look in the cache if the tile if the data is available
0055     for (uint i = 0; i < m_tilesCacheSize; i++) {
0056         if (x >= m_tilesCache[i]->area_x1 && x <= m_tilesCache[i]->area_x2 &&
0057                 y >= m_tilesCache[i]->area_y1 && y <= m_tilesCache[i]->area_y2) {
0058             KisTileInfo* kti = m_tilesCache[i];
0059             quint32 offset = x - kti->area_x1 + (y - kti->area_y1) * KisTileData::WIDTH;
0060             offset *= m_pixelSize;
0061             m_data = kti->data + offset;
0062             m_oldData = kti->oldData + offset;
0063             if (i > 0) {
0064                 memmove(m_tilesCache + 1, m_tilesCache, i * sizeof(KisTileInfo*));
0065                 m_tilesCache[0] = kti;
0066             }
0067             return;
0068         }
0069     }
0070     // The tile wasn't in cache
0071     if (m_tilesCacheSize == KisRandomAccessor2::CACHESIZE) { // Remove last element of cache
0072         unlockTile(m_tilesCache[CACHESIZE-1]->tile);
0073         unlockOldTile(m_tilesCache[CACHESIZE-1]->oldtile);
0074         delete m_tilesCache[CACHESIZE-1];
0075     } else {
0076         m_tilesCacheSize++;
0077     }
0078     quint32 col = xToCol(x);
0079     quint32 row = yToRow(y);
0080     KisTileInfo* kti = fetchTileData(col, row);
0081     quint32 offset = x - kti->area_x1 + (y - kti->area_y1) * KisTileData::WIDTH;
0082     offset *= m_pixelSize;
0083     m_data = kti->data + offset;
0084     m_oldData = kti->oldData + offset;
0085     memmove(m_tilesCache + 1, m_tilesCache, (KisRandomAccessor2::CACHESIZE - 1) * sizeof(KisTileInfo*));
0086     m_tilesCache[0] = kti;
0087 }
0088 
0089 
0090 quint8* KisRandomAccessor2::rawData()
0091 {
0092     return m_data;
0093 }
0094 
0095 
0096 const quint8* KisRandomAccessor2::oldRawData() const
0097 {
0098 #ifdef DEBUG
0099     if (!m_ktm->hasCurrentMemento()) warnTiles << "Accessing oldRawData() when no transaction is in progress.";
0100 #endif
0101     return m_oldData;
0102 }
0103 
0104 const quint8* KisRandomAccessor2::rawDataConst() const
0105 {
0106     return m_data;
0107 }
0108 
0109 KisRandomAccessor2::KisTileInfo* KisRandomAccessor2::fetchTileData(qint32 col, qint32 row)
0110 {
0111     KisTileInfo* kti = new KisTileInfo;
0112 
0113     m_ktm->getTilesPair(col, row, m_writable, &kti->tile, &kti->oldtile);
0114 
0115     lockTile(kti->tile);
0116     kti->data = kti->tile->data();
0117 
0118     lockOldTile(kti->oldtile);
0119     kti->oldData = kti->oldtile->data();
0120 
0121     kti->area_x1 = col * KisTileData::HEIGHT;
0122     kti->area_y1 = row * KisTileData::WIDTH;
0123     kti->area_x2 = kti->area_x1 + KisTileData::HEIGHT - 1;
0124     kti->area_y2 = kti->area_y1 + KisTileData::WIDTH - 1;
0125 
0126     return kti;
0127 }
0128 
0129 qint32 KisRandomAccessor2::numContiguousColumns(qint32 x) const
0130 {
0131     return m_ktm->numContiguousColumns(x - m_offsetX, 0, 0);
0132 }
0133 
0134 qint32 KisRandomAccessor2::numContiguousRows(qint32 y) const
0135 {
0136     return m_ktm->numContiguousRows(y - m_offsetY, 0, 0);
0137 }
0138 
0139 qint32 KisRandomAccessor2::rowStride(qint32 x, qint32 y) const
0140 {
0141     return m_ktm->rowStride(x - m_offsetX, y - m_offsetY);
0142 }
0143 
0144 qint32 KisRandomAccessor2::x() const
0145 {
0146     return m_lastX;
0147 }
0148 
0149 qint32 KisRandomAccessor2::y() const
0150 {
0151     return m_lastY;
0152 }