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 }