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 */