File indexing completed on 2024-05-19 04:26:26
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 KisWrappedRect::clipToWrapRect(KisPaintDeviceStrategy::extent(), 0256 m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0257 } 0258 0259 KisRegion region() const override { 0260 const WrapAroundAxis wrapAxis = m_device->defaultBounds()->wrapAroundModeAxis(); 0261 if (wrapAxis != WRAPAROUND_BOTH) { 0262 KisRegion region = KisPaintDeviceStrategy::region(); 0263 QVector<QRect> rects; 0264 Q_FOREACH (const QRect &rc, region.rects()) { 0265 const QRect clippedRect = KisWrappedRect::clipToWrapRect(rc, m_wrapRect, wrapAxis); 0266 if (!clippedRect.isEmpty()) { 0267 rects.append(clippedRect); 0268 } 0269 } 0270 region = KisRegion(rects); 0271 return region; 0272 } 0273 else { 0274 return KisPaintDeviceStrategy::region() & m_wrapRect; 0275 } 0276 } 0277 0278 void crop(const QRect &rect) override { 0279 KisPaintDeviceStrategy::crop(rect & m_wrapRect); 0280 } 0281 0282 void clear(const QRect &rect) override { 0283 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0284 Q_FOREACH (const QRect &rc, splitRect) { 0285 KisPaintDeviceStrategy::clear(rc); 0286 } 0287 } 0288 0289 void fill(const QRect &rect, const quint8 *fillPixel) override { 0290 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0291 Q_FOREACH (const QRect &rc, splitRect) { 0292 KisPaintDeviceStrategy::fill(rc, fillPixel); 0293 } 0294 } 0295 0296 KisHLineIteratorSP createHLineIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) override { 0297 KisWrappedRect splitRect(QRect(x, y, w, m_wrapRect.height()), m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0298 if (!splitRect.isSplit()) { 0299 return KisPaintDeviceStrategy::createHLineIteratorNG(dataManager, x, y, w, offsetX, offsetY); 0300 } 0301 return new KisWrappedHLineIterator(dataManager, splitRect, offsetX, offsetY, true, m_d->cacheInvalidator()); 0302 } 0303 0304 KisHLineConstIteratorSP createHLineConstIteratorNG(KisDataManager *dataManager, qint32 x, qint32 y, qint32 w, qint32 offsetX, qint32 offsetY) const override { 0305 KisWrappedRect splitRect(QRect(x, y, w, m_wrapRect.height()), m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0306 if (!splitRect.isSplit()) { 0307 return KisPaintDeviceStrategy::createHLineConstIteratorNG(dataManager, x, y, w, offsetX, offsetY); 0308 } 0309 return new KisWrappedHLineIterator(dataManager, splitRect, offsetX, offsetY, false, m_d->cacheInvalidator()); 0310 } 0311 0312 KisVLineIteratorSP createVLineIteratorNG(qint32 x, qint32 y, qint32 h) override { 0313 m_d->cache()->invalidate(); 0314 0315 KisWrappedRect splitRect(QRect(x, y, m_wrapRect.width(), h), m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0316 if (!splitRect.isSplit()) { 0317 return KisPaintDeviceStrategy::createVLineIteratorNG(x, y, h); 0318 } 0319 return new KisWrappedVLineIterator(m_d->dataManager().data(), splitRect, m_d->x(), m_d->y(), true, m_d->cacheInvalidator()); 0320 } 0321 0322 KisVLineConstIteratorSP createVLineConstIteratorNG(qint32 x, qint32 y, qint32 h) const override { 0323 KisWrappedRect splitRect(QRect(x, y, m_wrapRect.width(), h), m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0324 if (!splitRect.isSplit()) { 0325 return KisPaintDeviceStrategy::createVLineConstIteratorNG(x, y, h); 0326 } 0327 return new KisWrappedVLineIterator(m_d->dataManager().data(), splitRect, m_d->x(), m_d->y(), false, m_d->cacheInvalidator()); 0328 } 0329 0330 KisRandomAccessorSP createRandomAccessorNG() override { 0331 m_d->cache()->invalidate(); 0332 return new KisWrappedRandomAccessor( 0333 m_d->dataManager().data(), m_d->x(), m_d->y(), true, m_d->cacheInvalidator(), m_wrapRect, 0334 m_device->defaultBounds()->wrapAroundModeAxis()); 0335 } 0336 0337 KisRandomConstAccessorSP createRandomConstAccessorNG() const override { 0338 return new KisWrappedRandomAccessor( 0339 m_d->dataManager().data(), m_d->x(), m_d->y(), false, m_d->cacheInvalidator(), m_wrapRect, 0340 m_device->defaultBounds()->wrapAroundModeAxis()); 0341 } 0342 0343 void fastBitBltImpl(KisDataManagerSP srcDataManager, const QRect &rect) override { 0344 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0345 Q_FOREACH (const QRect &rc, splitRect) { 0346 KisPaintDeviceStrategy::fastBitBltImpl(srcDataManager, rc); 0347 } 0348 } 0349 0350 void fastBitBltOldData(KisPaintDeviceSP src, const QRect &rect) override { 0351 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0352 Q_FOREACH (const QRect &rc, splitRect) { 0353 KisPaintDeviceStrategy::fastBitBltOldData(src, rc); 0354 } 0355 } 0356 0357 void fastBitBltRoughImpl(KisDataManagerSP srcDataManager, const QRect &rect) override 0358 { 0359 // no rough version in wrapped mode 0360 fastBitBltImpl(srcDataManager, rect); 0361 } 0362 0363 void fastBitBltRoughOldData(KisPaintDeviceSP src, const QRect &rect) override { 0364 // no rough version in wrapped mode 0365 fastBitBltOldData(src, rect); 0366 } 0367 0368 void readBytes(quint8 *data, const QRect &rect) const override { 0369 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0370 0371 if (!splitRect.isSplit()) { 0372 KisPaintDeviceStrategy::readBytes(data, rect); 0373 } else { 0374 const int pixelSize = m_device->pixelSize(); 0375 0376 int leftWidth = splitRect[KisWrappedRect::TOPLEFT].width(); 0377 int rightWidth = splitRect[KisWrappedRect::TOPRIGHT].width(); 0378 0379 int totalHeight = rect.height(); 0380 int totalWidth = rect.width(); 0381 int dataRowStride = totalWidth * pixelSize; 0382 0383 int bufOffset = 0; 0384 int row = 0; 0385 while (row < totalHeight) { 0386 int leftIndex = KisWrappedRect::TOPLEFT + bufOffset; 0387 int rightIndex = KisWrappedRect::TOPRIGHT + bufOffset; 0388 0389 QPoint leftRectOrigin = splitRect[leftIndex].topLeft(); 0390 QPoint rightRectOrigin = splitRect[rightIndex].topLeft(); 0391 0392 int height = qMin(splitRect[leftIndex].height(), totalHeight - row); 0393 0394 int col = 0; 0395 while (col < totalWidth) { 0396 int width; 0397 quint8 *dataPtr; 0398 0399 width = qMin(leftWidth, totalWidth - col); 0400 dataPtr = data + pixelSize * (col + row * totalWidth); 0401 readBytesImpl(dataPtr, QRect(leftRectOrigin, QSize(width, height)), dataRowStride); 0402 col += width; 0403 0404 if (col >= totalWidth) break; 0405 0406 width = qMin(rightWidth, totalWidth - col); 0407 dataPtr = data + pixelSize * (col + row * totalWidth); 0408 readBytesImpl(dataPtr, QRect(rightRectOrigin, QSize(width, height)), dataRowStride); 0409 col += width; 0410 } 0411 0412 row += height; 0413 bufOffset = (bufOffset + 2) % 4; 0414 } 0415 } 0416 } 0417 0418 void writeBytes(const quint8 *data, const QRect &rect) override { 0419 KisWrappedRect splitRect(rect, m_wrapRect, m_device->defaultBounds()->wrapAroundModeAxis()); 0420 0421 if (!splitRect.isSplit()) { 0422 KisPaintDeviceStrategy::writeBytes(data, rect); 0423 } else { 0424 const int pixelSize = m_device->pixelSize(); 0425 0426 int totalWidth = rect.width(); 0427 int dataRowStride = totalWidth * pixelSize; 0428 0429 QRect rc; 0430 QPoint origin; 0431 const quint8 *dataPtr; 0432 0433 origin.rx() = 0; 0434 origin.ry() = 0; 0435 rc = splitRect.topLeft(); 0436 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0437 writeBytesImpl(dataPtr, rc, dataRowStride); 0438 0439 origin.rx() = splitRect.topLeft().width(); 0440 origin.ry() = 0; 0441 rc = splitRect.topRight(); 0442 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0443 writeBytesImpl(dataPtr, rc, dataRowStride); 0444 0445 origin.rx() = 0; 0446 origin.ry() = splitRect.topLeft().height(); 0447 rc = splitRect.bottomLeft(); 0448 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0449 writeBytesImpl(dataPtr, rc, dataRowStride); 0450 0451 origin.rx() = splitRect.topLeft().width(); 0452 origin.ry() = splitRect.topLeft().height(); 0453 rc = splitRect.bottomRight(); 0454 dataPtr = data + pixelSize * (origin.x() + totalWidth * origin.y()); 0455 writeBytesImpl(dataPtr, rc, dataRowStride); 0456 } 0457 } 0458 0459 private: 0460 QRect m_wrapRect; 0461 }; 0462 0463 0464 0465 #endif /* __KIS_PAINT_DEVICE_STRATEGIES_H */