/* * copyright (c) 2006 Cyrille Berger * * this program is free software; you can redistribute it and/or modify * it under the terms of the gnu general public license as published by * the free software foundation; either version 2 of the license, or * (at your option) any later version. * * this program is distributed in the hope that it will be useful, * but without any warranty; without even the implied warranty of * merchantability or fitness for a particular purpose. see the * gnu general public license for more details. * * you should have received a copy of the gnu general public license * along with this program; if not, write to the free software * foundation, inc., 675 mass ave, cambridge, ma 02139, usa. */ #include "kis_tiled_random_accessor.h" const TQ_UINT32 KisTiledRandomAccessor::CACHESIZE = 4; // Define the number of tiles we keep in cache KisTiledRandomAccessor::KisTiledRandomAccessor(KisTiledDataManager *ktm, TQ_INT32 x, TQ_INT32 y, bool writable) : m_ktm(ktm), m_tilesCache(new KisTileInfo*[4]), m_tilesCacheSize(0), m_pixelSize (m_ktm->pixelSize()), m_writable(writable) { Q_ASSERT(ktm != 0); moveTo(x, y); } KisTiledRandomAccessor::~KisTiledRandomAccessor() { for( uint i = 0; i < m_tilesCacheSize; i++) { m_tilesCache[i]->tile->removeReader(); m_tilesCache[i]->oldtile->removeReader(); delete m_tilesCache[i]; } delete m_tilesCache; } void KisTiledRandomAccessor::moveTo(TQ_INT32 x, TQ_INT32 y) { // Look in the cache if the tile if the data is available for( uint i = 0; i < m_tilesCacheSize; i++) { if( x >= m_tilesCache[i]->area_x1 && x <= m_tilesCache[i]->area_x2 && y >= m_tilesCache[i]->area_y1 && y <= m_tilesCache[i]->area_y2 ) { KisTileInfo* kti = m_tilesCache[i]; TQ_UINT32 offset = x - kti->area_x1 + (y -kti->area_y1) * KisTile::WIDTH; offset *= m_pixelSize; m_data = kti->data + offset; m_oldData = kti->oldData + offset; if(i > 0) { memmove(m_tilesCache+1,m_tilesCache, i * sizeof(KisTileInfo*)); m_tilesCache[0] = kti; } return; } } // The tile wasn't in cache if(m_tilesCacheSize == KisTiledRandomAccessor::CACHESIZE ) { // Remove last element of cache m_tilesCache[CACHESIZE-1]->tile->removeReader(); m_tilesCache[CACHESIZE-1]->oldtile->removeReader(); delete m_tilesCache[CACHESIZE-1]; } else { m_tilesCacheSize++; } TQ_UINT32 col = xToCol( x ); TQ_UINT32 row = yToRow( y ); KisTileInfo* kti = fetchTileData(col, row); TQ_UINT32 offset = x - kti->area_x1 + (y - kti->area_y1) * KisTile::WIDTH; offset *= m_pixelSize; m_data = kti->data + offset; m_oldData = kti->oldData + offset; memmove(m_tilesCache+1,m_tilesCache, (KisTiledRandomAccessor::CACHESIZE-1) * sizeof(KisTileInfo*)); m_tilesCache[0] = kti; } TQ_UINT8 * KisTiledRandomAccessor::rawData() const { return m_data; } const TQ_UINT8 * KisTiledRandomAccessor::oldRawData() const { #ifdef DEBUG kdWarning(!m_ktm->hasCurrentMemento(), DBG_AREA_TILES) << "Accessing oldRawData() when no transaction is in progress.\n"; #endif return m_oldData; } KisTiledRandomAccessor::KisTileInfo* KisTiledRandomAccessor::fetchTileData(TQ_INT32 col, TQ_INT32 row) { KisTileInfo* kti = new KisTileInfo; kti->tile = m_ktm->getTile(col, row, m_writable); kti->tile->addReader(); kti->data = kti->tile->data(); kti->area_x1 = col * KisTile::HEIGHT; kti->area_y1 = row * KisTile::WIDTH; kti->area_x2 = kti->area_x1 + KisTile::HEIGHT - 2; kti->area_y2 = kti->area_y1 + KisTile::WIDTH - 2; // set old data kti->oldtile = m_ktm->getOldTile(col, row, kti->tile); kti->oldtile->addReader(); kti->oldData = kti->oldtile->data(); return kti; }