File indexing completed on 2024-06-09 04:22:22

0001 /*
0002  *  SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_hline_iterator.h"
0008 
0009 
0010 KisHLineIterator2::KisHLineIterator2(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY, bool writable, KisIteratorCompleteListener *completionListener)
0011     : KisBaseIterator(dataManager, writable, completionListener),
0012       m_offsetX(offsetX),
0013       m_offsetY(offsetY)
0014 {
0015     x -= m_offsetX;
0016     y -= m_offsetY;
0017     Q_ASSERT(dataManager);
0018 
0019     if (w < 1) w = 1;  // To make sure there's always at least one pixel read.
0020 
0021     m_x = x;
0022     m_y = y;
0023 
0024     m_left = x;
0025     m_right = x + w - 1;
0026 
0027     m_top = y;
0028 
0029     m_havePixels = (w == 0) ? false : true;
0030     if (m_left > m_right) {
0031         m_havePixels = false;
0032         return;
0033     }
0034 
0035     m_leftCol = xToCol(m_left);
0036     m_rightCol = xToCol(m_right);
0037 
0038     m_row = yToRow(m_y);
0039     m_yInTile = calcYInTile(m_y, m_row);
0040 
0041     m_leftInLeftmostTile = m_left - m_leftCol * KisTileData::WIDTH;
0042 
0043     m_tilesCacheSize = m_rightCol - m_leftCol + 1;
0044     m_tilesCache.resize(m_tilesCacheSize);
0045 
0046     m_tileWidth = m_pixelSize * KisTileData::HEIGHT;
0047 
0048     // let's preallocate first row
0049     for (quint32 i = 0; i < m_tilesCacheSize; i++){
0050         fetchTileDataForCache(m_tilesCache[i], m_leftCol + i, m_row);
0051     }
0052     m_index = 0;
0053     switchToTile(m_leftInLeftmostTile);
0054 }
0055 
0056 void KisHLineIterator2::resetPixelPos()
0057 {
0058     m_x = m_left;
0059 
0060     m_index = 0;
0061     switchToTile(m_leftInLeftmostTile);
0062 
0063     m_havePixels = true;
0064 }
0065 
0066 void KisHLineIterator2::resetRowPos()
0067 {
0068     m_y = m_top;
0069 
0070     m_row = yToRow(m_y);
0071     m_yInTile = calcYInTile(m_y, m_row);
0072     preallocateTiles();
0073 
0074     resetPixelPos();
0075 }
0076 
0077 bool KisHLineIterator2::nextPixel()
0078 {
0079     // We won't increment m_x here as integer can overflow here
0080     if (m_x >= m_right) {
0081         //return !m_isDoneFlag;
0082         return m_havePixels = false;
0083     } else {
0084         ++m_x;
0085         m_data += m_pixelSize;
0086         if (m_x <= m_rightmostInTile)
0087             m_oldData += m_pixelSize;
0088         else {
0089             // Switching to the beginning of the next tile
0090             ++m_index;
0091             switchToTile(0);
0092         }
0093     }
0094 
0095     return m_havePixels;
0096 }
0097 
0098 
0099 void KisHLineIterator2::nextRow()
0100 {
0101     m_x = m_left;
0102     ++m_y;
0103 
0104     if (++m_yInTile < KisTileData::HEIGHT) {
0105         /* do nothing, usual case */
0106     } else {
0107         ++m_row;
0108         m_yInTile = 0;
0109         preallocateTiles();
0110     }
0111     m_index = 0;
0112     switchToTile(m_leftInLeftmostTile);
0113 
0114     m_havePixels = true;
0115 }
0116 
0117 
0118 qint32 KisHLineIterator2::nConseqPixels() const
0119 {
0120     return qMin(m_rightmostInTile, m_right) - m_x + 1;
0121 }
0122 
0123 
0124 
0125 bool KisHLineIterator2::nextPixels(qint32 n)
0126 {
0127     Q_ASSERT_X(!(m_x > 0 && (m_x + n) < 0), "hlineIt+=", "Integer overflow");
0128 
0129     qint32 previousCol = xToCol(m_x);
0130     // We won't increment m_x here first as integer can overflow
0131     if (m_x >= m_right || (m_x += n) > m_right) {
0132         m_havePixels = false;
0133     } else {
0134         qint32 col = xToCol(m_x);
0135         // if we are in the same column in tiles
0136         if (col == previousCol) {
0137             m_data += n * m_pixelSize;
0138         } else {
0139             qint32 xInTile = calcXInTile(m_x, col);
0140             m_index += col - previousCol;
0141             switchToTile(xInTile);
0142         }
0143     }
0144     return m_havePixels;
0145 }
0146 
0147 
0148 
0149 KisHLineIterator2::~KisHLineIterator2()
0150 {
0151     for (uint i = 0; i < m_tilesCacheSize; i++) {
0152         unlockTile(m_tilesCache[i].tile);
0153         unlockOldTile(m_tilesCache[i].oldtile);
0154     }
0155 }
0156 
0157 
0158 quint8* KisHLineIterator2::rawData()
0159 {
0160     return m_data;
0161 }
0162 
0163 
0164 const quint8* KisHLineIterator2::oldRawData() const
0165 {
0166     return m_oldData;
0167 }
0168 
0169 const quint8* KisHLineIterator2::rawDataConst() const
0170 {
0171     return m_data;
0172 }
0173 
0174 void KisHLineIterator2::switchToTile(qint32 xInTile)
0175 {
0176     // The caller must ensure that we are not out of bounds
0177     Q_ASSERT(m_index < m_tilesCacheSize);
0178 
0179     m_data = m_tilesCache[m_index].data;
0180     m_oldData = m_tilesCache[m_index].oldData;
0181 
0182     int offset_row = m_pixelSize * (m_yInTile * KisTileData::WIDTH);
0183     m_data += offset_row;
0184     m_rightmostInTile = (m_leftCol + m_index + 1) * KisTileData::WIDTH - 1;
0185     int offset_col = m_pixelSize * xInTile;
0186     m_data  += offset_col;
0187     m_oldData += offset_row + offset_col;
0188 }
0189 
0190 
0191 void KisHLineIterator2::fetchTileDataForCache(KisTileInfo& kti, qint32 col, qint32 row)
0192 {
0193     m_dataManager->getTilesPair(col, row, m_writable, &kti.tile, &kti.oldtile);
0194 
0195     lockTile(kti.tile);
0196     kti.data = kti.tile->data();
0197 
0198     lockOldTile(kti.oldtile);
0199     kti.oldData = kti.oldtile->data();
0200 }
0201 
0202 void KisHLineIterator2::preallocateTiles()
0203 {
0204     for (quint32 i = 0; i < m_tilesCacheSize; ++i){
0205         unlockTile(m_tilesCache[i].tile);
0206         unlockOldTile(m_tilesCache[i].oldtile);
0207         fetchTileDataForCache(m_tilesCache[i], m_leftCol + i, m_row);
0208     }
0209 }
0210 
0211 qint32 KisHLineIterator2::x() const
0212 {
0213     return m_x + m_offsetX;
0214 }
0215 
0216 qint32 KisHLineIterator2::y() const
0217 {
0218     return m_y + m_offsetY;
0219 }