File indexing completed on 2024-05-12 15:58:32
0001 /* 0002 * SPDX-FileCopyrightText: 2013 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef __KIS_PAINT_DEVICE_STRATEGIES_H 0008 #define __KIS_PAINT_DEVICE_STRATEGIES_H 0009 0010 #include "kis_wrapped_rect.h" 0011 #include "kis_wrapped_hline_iterator.h" 0012 #include "kis_wrapped_vline_iterator.h" 0013 #include "kis_wrapped_random_accessor.h" 0014 0015 0016 class KisPaintDevice::Private::KisPaintDeviceStrategy 0017 { 0018 public: 0019 KisPaintDeviceStrategy(KisPaintDevice *device, 0020 KisPaintDevice::Private *d) 0021 : m_device(device), m_d(d) 0022 { 0023 } 0024 0025 virtual ~KisPaintDeviceStrategy() { 0026 } 0027 0028 virtual void move(const QPoint& pt) { 0029 m_d->setX(pt.x()); 0030 m_d->setY(pt.y()); 0031 m_d->cache()->invalidate(); 0032 } 0033 0034 virtual QRect extent() const { 0035 QRect extent; 0036 0037 qint32 x, y, w, h; 0038 m_d->dataManager()->extent(x, y, w, h); 0039 x += m_d->x(); 0040 y += m_d->y(); 0041 extent = QRect(x, y, w, h); 0042 0043 quint8 defaultOpacity = m_device->defaultPixel().opacityU8(); 0044 0045 if (defaultOpacity != OPACITY_TRANSPARENT_U8) 0046 extent |= m_d->defaultBounds->bounds(); 0047 0048 return extent; 0049 } 0050 0051 virtual KisRegion region() const { 0052 return m_d->cache()->region().translated(m_d->x(), m_d->y()); 0053 } 0054 0055 virtual void crop(const QRect &rect) { 0056 m_d->dataManager()->setExtent(rect.translated(-m_d->x(), -m_d->y())); 0057 m_d->cache()->invalidate(); 0058 } 0059 0060 virtual void clear(const QRect & rc) { 0061 KisDataManagerSP dm = m_d->dataManager(); 0062 0063 dm->clear(rc.x() - m_d->x(), rc.y() - m_d->y(), 0064 rc.width(), rc.height(), 0065 dm->defaultPixel()); 0066 m_d->cache()->invalidate(); 0067 } 0068 0069 virtual void fill(const QRect &rc, const quint8 *fillPixel) { 0070 m_d->dataManager()->clear(rc.x() - m_d->x(), 0071 rc.y() - m_d->y(), 0072 rc.width(), 0073 rc.height(), 0074 fillPixel); 0075 m_d->cache()->invalidate(); 0076 } 0077 0078 0079 virtual KisHLineIteratorSP createHLineIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) { 0080 return new KisHLineIterator2(dataManager, x, y, w, offsetX, offsetY, true, m_d->cacheInvalidator()); 0081 } 0082 0083 virtual KisHLineConstIteratorSP createHLineConstIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) const { 0084 return new KisHLineIterator2(dataManager, x, y, w, offsetX, offsetY, false, m_d->cacheInvalidator()); 0085 } 0086 0087 0088 virtual KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 w) { 0089 m_d->cache()->invalidate(); 0090 return new KisVLineIterator2(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y(), true, m_d->cacheInvalidator()); 0091 } 0092 0093 virtual KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const { 0094 return new KisVLineIterator2(m_d->dataManager().data(), x, y, w, m_d->x(), m_d->y(), false, m_d->cacheInvalidator()); 0095 } 0096 0097 virtual KisRandomAccessorSP createRandomAccessorNG() { 0098 m_d->cache()->invalidate(); 0099 return new KisRandomAccessor2(m_d->dataManager().data(), m_d->x(), m_d->y(), true, m_d->cacheInvalidator()); 0100 } 0101 0102 virtual KisRandomConstAccessorSP createRandomConstAccessorNG() const { 0103 return new KisRandomAccessor2(m_d->dataManager().data(), m_d->x(), m_d->y(), false, m_d->cacheInvalidator()); 0104 } 0105 0106 virtual void fastBitBlt(KisPaintDeviceSP src, const QRect &rect) { 0107 Q_ASSERT(m_device->fastBitBltPossible(src)); 0108 fastBitBltImpl(src->dataManager(), rect); 0109 } 0110 0111 virtual void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect) { 0112 Q_ASSERT(m_device->fastBitBltPossible(src)); 0113 0114 m_d->dataManager()->bitBltOldData(src->dataManager(), rect.translated(-m_d->x(), -m_d->y())); 0115 m_d->cache()->invalidate(); 0116 } 0117 0118 virtual void fastBitBltRough(KisPaintDeviceSP src, const QRect &rect) { 0119 Q_ASSERT(m_device->fastBitBltPossible(src)); 0120 fastBitBltRoughImpl(src->dataManager(), rect); 0121 } 0122 0123 virtual void fastBitBltRough(KisDataManagerSP srcDataManager, const QRect &rect) { 0124 fastBitBltRoughImpl(srcDataManager, rect); 0125 } 0126 0127 virtual void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect) { 0128 Q_ASSERT(m_device->fastBitBltPossible(src)); 0129 0130 m_d->dataManager()->bitBltRoughOldData(src->dataManager(), rect.translated(-m_d->x(), -m_d->y())); 0131 m_d->cache()->invalidate(); 0132 } 0133 0134 virtual void readBytes(quint8 *data, const QRect &rect) const { 0135 readBytesImpl(data, rect, -1); 0136 } 0137 0138 virtual void writeBytes(const quint8 * data, const QRect &rect) { 0139 writeBytesImpl(data, rect, -1); 0140 } 0141 0142 virtual QVector<quint8*> readPlanarBytes(qint32 x, qint32 y, qint32 w, qint32 h) const { 0143 return m_d->dataManager()->readPlanarBytes(m_device->channelSizes(), x, y, w, h); 0144 } 0145 0146 virtual void writePlanarBytes(QVector<quint8*> planes, qint32 x, qint32 y, qint32 w, qint32 h) { 0147 m_d->dataManager()->writePlanarBytes(planes, m_device->channelSizes(), x, y, w, h); 0148 m_d->cache()->invalidate(); 0149 } 0150 protected: 0151 virtual void readBytesImpl(quint8 *data, const QRect &rect, int dataRowStride) const { 0152 m_d->dataManager()->readBytes(data, 0153 rect.x() - m_d->x(), 0154 rect.y() - m_d->y(), 0155 rect.width(), 0156 rect.height(), 0157 dataRowStride); 0158 } 0159 0160 virtual void writeBytesImpl(const quint8 * data, const QRect &rect, int dataRowStride) { 0161 m_d->dataManager()->writeBytes(data, 0162 rect.x() - m_d->x(), 0163 rect.y() - m_d->y(), 0164 rect.width(), 0165 rect.height(), 0166 dataRowStride); 0167 m_d->cache()->invalidate(); 0168 } 0169 0170 virtual void fastBitBltImpl(KisDataManagerSP srcDataManager, const QRect &rect) 0171 { 0172 m_d->dataManager()->bitBlt(srcDataManager, rect.translated(-m_d->x(), -m_d->y())); 0173 m_d->cache()->invalidate(); 0174 } 0175 0176 virtual void fastBitBltRoughImpl(KisDataManagerSP srcDataManager, const QRect &rect) 0177 { 0178 m_d->dataManager()->bitBltRough(srcDataManager, rect.translated(-m_d->x(), -m_d->y())); 0179 m_d->cache()->invalidate(); 0180 } 0181 0182 protected: 0183 KisPaintDevice *m_device; 0184 KisPaintDevice::Private * const m_d; 0185 }; 0186 0187 0188 class KisPaintDevice::Private::KisPaintDeviceWrappedStrategy : public KisPaintDeviceStrategy 0189 { 0190 public: 0191 KisPaintDeviceWrappedStrategy(const QRect &wrapRect, 0192 KisPaintDevice *device, 0193 KisPaintDevice::Private *d) 0194 : KisPaintDeviceStrategy(device, d), 0195 m_wrapRect(wrapRect) 0196 { 0197 } 0198 0199 const QRect wrapRect() const { 0200 return m_wrapRect; 0201 } 0202 0203 void setWrapRect(const QRect &rc) { 0204 m_wrapRect = rc; 0205 } 0206 0207 void move(const QPoint& pt) override { 0208 QPoint offset (pt.x() - m_device->x(), pt.y() - m_device->y()); 0209 0210 QRect exactBoundsBeforeMove = m_device->exactBounds(); 0211 KisPaintDeviceStrategy::move(pt); 0212 0213 QRegion borderRegion(exactBoundsBeforeMove.translated(offset.x(), offset.y())); 0214 borderRegion -= m_wrapRect; 0215 0216 const int pixelSize = m_device->pixelSize(); 0217 0218 auto rectIter = borderRegion.begin(); 0219 while (rectIter != borderRegion.end()) { 0220 QRect rc = *rectIter; 0221 KisRandomConstAccessorSP srcIt = KisPaintDeviceStrategy::createRandomConstAccessorNG(); 0222 KisRandomAccessorSP dstIt = createRandomAccessorNG(); 0223 0224 int rows = 1; 0225 int columns = 1; 0226 0227 for (int y = rc.y(); y <= rc.bottom(); y += rows) { 0228 int rows = qMin(srcIt->numContiguousRows(y), dstIt->numContiguousRows(y)); 0229 rows = qMin(rows, rc.bottom() - y + 1); 0230 0231 for (int x = rc.x(); x <= rc.right(); x += columns) { 0232 int columns = qMin(srcIt->numContiguousColumns(x), dstIt->numContiguousColumns(x)); 0233 columns = qMin(columns, rc.right() - x + 1); 0234 0235 srcIt->moveTo(x, y); 0236 dstIt->moveTo(x, y); 0237 0238 int srcRowStride = srcIt->rowStride(x, y); 0239 int dstRowStride = dstIt->rowStride(x, y); 0240 const quint8 *srcPtr = srcIt->rawDataConst(); 0241 quint8 *dstPtr = dstIt->rawData(); 0242 0243 for (int i = 0; i < rows; i++) { 0244 memcpy(dstPtr, srcPtr, pixelSize * columns); 0245 srcPtr += srcRowStride; 0246 dstPtr += dstRowStride; 0247 } 0248 } 0249 } 0250 rectIter++; 0251 } 0252 } 0253 0254 QRect extent() const override { 0255 return KisPaintDeviceStrategy::extent() & m_wrapRect; 0256 } 0257 0258 KisRegion region() const override { 0259 return KisPaintDeviceStrategy::region() & m_wrapRect; 0260 } 0261 0262 void crop(const QRect &rect) override { 0263 KisPaintDeviceStrategy::crop(rect & m_wrapRect); 0264 } 0265 0266 void clear(const QRect &rect) override { 0267 KisWrappedRect splitRect(rect, m_wrapRect); 0268 Q_FOREACH (const QRect &rc, splitRect) { 0269 KisPaintDeviceStrategy::clear(rc); 0270 } 0271 } 0272 0273 void fill(const QRect &rect, const quint8 *fillPixel) override { 0274 KisWrappedRect splitRect(rect, m_wrapRect); 0275 Q_FOREACH (const QRect &rc, splitRect) { 0276 KisPaintDeviceStrategy::fill(rc, fillPixel); 0277 } 0278 } 0279 0280 KisHLineIteratorSP createHLineIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) override { 0281 KisWrappedRect splitRect(QRect(x, y, w, m_wrapRect.height()), m_wrapRect); 0282 if (!splitRect.isSplit()) { 0283 return KisPaintDeviceStrategy::createHLineIteratorNG(dataManager, x, y, w, offsetX, offsetY); 0284 } 0285 return new KisWrappedHLineIterator(dataManager, splitRect, offsetX, offsetY, true, m_d->cacheInvalidator()); 0286 } 0287 0288 KisHLineConstIteratorSP createHLineConstIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) const override { 0289 KisWrappedRect splitRect(QRect(x, y, w, m_wrapRect.height()), m_wrapRect); 0290 if (!splitRect.isSplit()) { 0291 return KisPaintDeviceStrategy::createHLineConstIteratorNG(dataManager, x, y, w, offsetX, offsetY); 0292 } 0293 return new KisWrappedHLineIterator(dataManager, splitRect, offsetX, offsetY, false, m_d->cacheInvalidator()); 0294 } 0295 0296 KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h) override { 0297 m_d->cache()->invalidate(); 0298 0299 KisWrappedRect splitRect(QRect(x, y, m_wrapRect.width(), h), m_wrapRect); 0300 if (!splitRect.isSplit()) { 0301 return KisPaintDeviceStrategy::createVLineIteratorNG(x, y, h); 0302 } 0303 return new KisWrappedVLineIterator(m_d->dataManager().data(), splitRect, m_d->x(), m_d->y(), true, m_d->cacheInvalidator()); 0304 } 0305 0306 KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const override { 0307 KisWrappedRect splitRect(QRect(x, y, m_wrapRect.width(), h), m_wrapRect); 0308 if (!splitRect.isSplit()) { 0309 return KisPaintDeviceStrategy::createVLineConstIteratorNG(x, y, h); 0310 } 0311 return new KisWrappedVLineIterator(m_d->dataManager().data(), splitRect, m_d->x(), m_d->y(), false, m_d->cacheInvalidator()); 0312 } 0313 0314 KisRandomAccessorSP createRandomAccessorNG() override { 0315 m_d->cache()->invalidate(); 0316 return new KisWrappedRandomAccessor(m_d->dataManager().data(), m_d->x(), m_d->y(), true, m_d->cacheInvalidator(), m_wrapRect); 0317 } 0318 0319 KisRandomConstAccessorSP createRandomConstAccessorNG() const override { 0320 return new KisWrappedRandomAccessor(m_d->dataManager().data(), m_d->x(), m_d->y(), false, m_d->cacheInvalidator(), m_wrapRect); 0321 } 0322 0323 void fastBitBltImpl(KisDataManagerSP srcDataManager, const QRect &rect) override { 0324 KisWrappedRect splitRect(rect, m_wrapRect); 0325 Q_FOREACH (const QRect &rc, splitRect) { 0326 KisPaintDeviceStrategy::fastBitBltImpl(srcDataManager, rc); 0327 } 0328 } 0329 0330 void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect) override { 0331 KisWrappedRect splitRect(rect, m_wrapRect); 0332 Q_FOREACH (const QRect &rc, splitRect) { 0333 KisPaintDeviceStrategy::fastBitBltOldData(src, rc); 0334 } 0335 } 0336 0337 void fastBitBltRoughImpl(KisDataManagerSP srcDataManager, const QRect &rect) override 0338 { 0339 // no rough version in wrapped mode 0340 fastBitBltImpl(srcDataManager, rect); 0341 } 0342 0343 void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect) override { 0344 // no rough version in wrapped mode 0345 fastBitBltOldData(src, rect); 0346 } 0347 0348 void readBytes(quint8 *data, const QRect &rect) const override { 0349 KisWrappedRect splitRect(rect, m_wrapRect); 0350 0351 if (!splitRect.isSplit()) { 0352 KisPaintDeviceStrategy::readBytes(data, rect); 0353 } else { 0354 const int pixelSize = m_device->pixelSize(); 0355 0356 int leftWidth = splitRect[KisWrappedRect::TOPLEFT].width(); 0357 int rightWidth = splitRect[KisWrappedRect::TOPRIGHT].width(); 0358 0359 int totalHeight = rect.height(); 0360 int totalWidth = rect.width(); 0361 int dataRowStride = totalWidth * pixelSize; 0362 0363 int bufOffset = 0; 0364 int row = 0; 0365 while (row < totalHeight) { 0366 int leftIndex = KisWrappedRect::TOPLEFT + bufOffset; 0367 int rightIndex = KisWrappedRect::TOPRIGHT + bufOffset; 0368 0369 QPoint leftRectOrigin = splitRect[leftIndex].topLeft(); 0370 QPoint rightRectOrigin = splitRect[rightIndex].topLeft(); 0371 0372 int height = qMin(splitRect[leftIndex].height(), totalHeight - row); 0373 0374 int col = 0; 0375 while (col < totalWidth) { 0376 int width; 0377 quint8 *dataPtr; 0378 0379 width = qMin(leftWidth, totalWidth - col); 0380 dataPtr = data + pixelSize * (col + row * totalWidth); 0381 readBytesImpl(dataPtr, QRect(leftRectOrigin, QSize(width, height)), dataRowStride); 0382 col += width; 0383 0384 if (col >= totalWidth) break; 0385 0386 width = qMin(rightWidth, totalWidth - col); 0387 dataPtr = data + pixelSize * (col + row * totalWidth); 0388 readBytesImpl(dataPtr, QRect(rightRectOrigin, QSize(width, height)), dataRowStride); 0389 col += width; 0390 } 0391 0392 row += height; 0393 bufOffset = (bufOffset + 2) % 4; 0394 } 0395 } 0396 } 0397 0398 void writeBytes(const quint8 *data, const QRect &rect) override { 0399 KisWrappedRect splitRect(rect, m_wrapRect); 0400 0401 if (!splitRect.isSplit()) { 0402 KisPaintDeviceStrategy::writeBytes(data, rect); 0403 } else { 0404 const int pixelSize = m_device->pixelSize(); 0405 0406 int totalWidth = rect.width(); 0407 int dataRowStride = totalWidth * pixelSize; 0408 0409 QRect rc; 0410 QPoint origin; 0411 const quint8 *dataPtr; 0412 0413 origin.rx() = 0; 0414 origin.ry() = 0; 0415 rc = splitRect.topLeft(); 0416 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0417 writeBytesImpl(dataPtr, rc, dataRowStride); 0418 0419 origin.rx() = splitRect.topLeft().width(); 0420 origin.ry() = 0; 0421 rc = splitRect.topRight(); 0422 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0423 writeBytesImpl(dataPtr, rc, dataRowStride); 0424 0425 origin.rx() = 0; 0426 origin.ry() = splitRect.topLeft().height(); 0427 rc = splitRect.bottomLeft(); 0428 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0429 writeBytesImpl(dataPtr, rc, dataRowStride); 0430 0431 origin.rx() = splitRect.topLeft().width(); 0432 origin.ry() = splitRect.topLeft().height(); 0433 rc = splitRect.bottomRight(); 0434 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0435 writeBytesImpl(dataPtr, rc, dataRowStride); 0436 } 0437 } 0438 0439 private: 0440 QRect m_wrapRect; 0441 }; 0442 0443 0444 0445 #endif /* __KIS_PAINT_DEVICE_STRATEGIES_H */