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