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 }