File indexing completed on 2024-12-22 04:10:18

0001 /*
0002  *  SPDX-FileCopyrightText: 2007 Boudewijn Rempt <boud@valdyas.org>
0003  *  SPDX-FileCopyrightText: 2010 Cyrille Berger <cberger@cberger.net>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "kis_iterators_ng_test.h"
0009 #include <QApplication>
0010 
0011 #include <simpletest.h>
0012 #include <KoColor.h>
0013 #include <KoColorSpace.h>
0014 #include <KoColorSpaceRegistry.h>
0015 #include <KoColorProfile.h>
0016 
0017 #include "kis_random_accessor_ng.h"
0018 #include "kis_random_sub_accessor.h"
0019 
0020 #include "kis_paint_device.h"
0021 #include <kis_iterator_ng.h>
0022 #include "kis_global.h"
0023 #include <testutil.h>
0024 #include <testimage.h>
0025 
0026 void KisIteratorNGTest::allCsApplicator(void (KisIteratorNGTest::* funcPtr)(const KoColorSpace*cs))
0027 {
0028     QList<const KoColorSpace*> colorspaces = KoColorSpaceRegistry::instance()->allColorSpaces(KoColorSpaceRegistry::AllColorSpaces, KoColorSpaceRegistry::OnlyDefaultProfile);
0029 
0030     Q_FOREACH (const KoColorSpace* cs, colorspaces) {
0031 
0032         dbgKrita << "Testing with" << cs->id();
0033         if (cs->id() != "GRAYU16") // No point in testing extend for GRAYU16
0034             (this->*funcPtr)(cs);
0035     }
0036 }
0037 
0038 inline quint8* allocatePixels(const KoColorSpace *colorSpace, int numPixels)
0039 {
0040     quint8 * bytes = new quint8[colorSpace->pixelSize() * 64 * 64 * 10];
0041     KoColor color(Qt::red, colorSpace);
0042     const int pixelSize = colorSpace->pixelSize();
0043     for(int i = 0; i < numPixels; i++) {
0044         memcpy(bytes + i * pixelSize, color.data(), pixelSize);
0045     }
0046 
0047     return bytes;
0048 }
0049 
0050 void KisIteratorNGTest::writeBytes(const KoColorSpace * colorSpace)
0051 {
0052 
0053 
0054     KisPaintDevice dev(colorSpace);
0055 
0056     QCOMPARE(dev.extent(), QRect());
0057 
0058     // Check allocation on tile boundaries
0059 
0060     // Allocate memory for a 2 * 5 tiles grid
0061     QScopedArrayPointer<quint8> bytes(allocatePixels(colorSpace, 64 * 64 * 10));
0062 
0063     // Covers 5 x 2 tiles
0064     dev.writeBytes(bytes.data(), 0, 0, 5 * 64, 2 * 64);
0065 
0066     // Covers
0067     QCOMPARE(dev.extent(), QRect(0, 0, 64 * 5, 64 * 2));
0068     QCOMPARE(dev.exactBounds(), QRect(0, 0, 64 * 5, 64 * 2));
0069 
0070     dev.clear();
0071     QCOMPARE(dev.extent(), QRect());
0072 
0073     dev.clear();
0074     // Covers three by three tiles
0075     dev.writeBytes(bytes.data(), 10, 10, 130, 130);
0076 
0077     QCOMPARE(dev.extent(), QRect(0, 0, 64 * 3, 64 * 3));
0078     QCOMPARE(dev.exactBounds(), QRect(10, 10, 130, 130));
0079 
0080     dev.clear();
0081     // Covers 11 x 2 tiles
0082     dev.writeBytes(bytes.data(), -10, -10, 10 * 64, 64);
0083 
0084     QCOMPARE(dev.extent(), QRect(-64, -64, 64 * 11, 64 * 2));
0085     QCOMPARE(dev.exactBounds(), QRect(-10, -10, 640, 64));
0086 }
0087 
0088 void KisIteratorNGTest::fill(const KoColorSpace * colorSpace)
0089 {
0090 
0091     KisPaintDevice dev(colorSpace);
0092 
0093     QCOMPARE(dev.extent(), QRect());
0094 
0095     QScopedArrayPointer<quint8> bytes(allocatePixels(colorSpace, 1));
0096 
0097     dev.fill(0, 0, 5, 5, bytes.data());
0098     QCOMPARE(dev.extent(), QRect(0, 0, 64, 64));
0099     QCOMPARE(dev.exactBounds(), QRect(0, 0, 5, 5));
0100 
0101     dev.clear();
0102     dev.fill(5, 5, 5, 5, bytes.data());
0103     QCOMPARE(dev.extent(), QRect(0, 0, 64, 64));
0104     QCOMPARE(dev.exactBounds(), QRect(5, 5, 5, 5));
0105 
0106     dev.clear();
0107     dev.fill(5, 5, 500, 500, bytes.data());
0108     QCOMPARE(dev.extent(), QRect(0, 0, 8 * 64, 8 * 64));
0109     QCOMPARE(dev.exactBounds(), QRect(5, 5, 500, 500));
0110 
0111     dev.clear();
0112     dev.fill(33, -10, 348, 1028, bytes.data());
0113     QCOMPARE(dev.extent(), QRect(0, -64, 6 * 64, 17 * 64));
0114     QCOMPARE(dev.exactBounds(), QRect(33, -10, 348, 1028));
0115 }
0116 
0117 void KisIteratorNGTest::sequentialIter(const KoColorSpace * colorSpace)
0118 {
0119 
0120     KisPaintDeviceSP dev = new KisPaintDevice(colorSpace);
0121 
0122     QCOMPARE(dev->extent(), QRect());
0123 
0124     // Const does not extend the extent
0125     {
0126         KisSequentialConstIterator it(dev, QRect(0, 0, 128, 128));
0127         while (it.nextPixel());
0128         QCOMPARE(dev->extent(), QRect());
0129         QCOMPARE(dev->exactBounds(), QRect(QPoint(0, 0), QPoint(-1, -1)));
0130     }
0131 
0132     // Non-const does
0133     {
0134         KisSequentialIterator it(dev, QRect(0, 0, 128, 128));
0135         int i = -1;
0136 
0137         while (it.nextPixel()) {
0138             i++;
0139             KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
0140             memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
0141 
0142             QCOMPARE(it.x(), i % 128);
0143             QCOMPARE(it.y(), i / 128);
0144         }
0145 
0146         QCOMPARE(dev->extent(), QRect(0, 0, 128, 128));
0147         QCOMPARE(dev->exactBounds(), QRect(0, 0, 128, 128));
0148     }
0149 
0150     { // check const iterator
0151         KisSequentialConstIterator it(dev, QRect(0, 0, 128, 128));
0152         int i = -1;
0153 
0154         while (it.nextPixel()) {
0155             i++;
0156             KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
0157             QVERIFY(memcmp(it.rawDataConst(), c.data(), colorSpace->pixelSize()) == 0);
0158         }
0159 
0160         QCOMPARE(dev->extent(), QRect(0, 0, 128, 128));
0161         QCOMPARE(dev->exactBounds(), QRect(0, 0, 128, 128));
0162     }
0163 
0164     { // check const iterator with **empty** area! It should neither crash nor enter the loop
0165         KisSequentialConstIterator it(dev, QRect());
0166 
0167         QVERIFY(!it.rawDataConst());
0168         QVERIFY(!it.oldRawData());
0169 
0170         while (it.nextPixel()) {
0171             QVERIFY(0 && "we should never enter the loop");
0172         }
0173     }
0174 
0175     { // check const iterator with strides
0176         KisSequentialConstIterator it(dev, QRect(0, 0, 128, 128));
0177         int i = -1;
0178 
0179         int numConseqPixels = it.nConseqPixels();
0180         while (it.nextPixels(numConseqPixels)) {
0181 
0182             numConseqPixels = it.nConseqPixels();
0183 
0184             for (int j = 0; j < numConseqPixels; j++) {
0185                 i++;
0186                 KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
0187                 QVERIFY(memcmp(it.rawDataConst() + j * colorSpace->pixelSize(),
0188                                c.data(),
0189                                colorSpace->pixelSize()) == 0);
0190             }
0191         }
0192 
0193         QCOMPARE(dev->extent(), QRect(0, 0, 128, 128));
0194         QCOMPARE(dev->exactBounds(), QRect(0, 0, 128, 128));
0195     }
0196 
0197     { // check const iterator with strides and **empty** area
0198         KisSequentialConstIterator it(dev, QRect());
0199 
0200         QVERIFY(!it.rawDataConst());
0201         QVERIFY(!it.oldRawData());
0202 
0203         int numConseqPixels = it.nConseqPixels();
0204         while (it.nextPixels(numConseqPixels)) {
0205             QVERIFY(0 && "we should never enter the loop");
0206         }
0207     }
0208 
0209     dev->clear();
0210 
0211     {
0212         KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
0213         int i = -1;
0214 
0215         while (it.nextPixel()) {
0216             i++;
0217             KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
0218 
0219             memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
0220         }
0221 
0222         QCOMPARE(dev->extent(), QRect(0, 0, 3 * 64, 3 * 64));
0223         QCOMPARE(dev->exactBounds(), QRect(10, 10, 128, 128));
0224     }
0225 
0226     dev->clear();
0227     dev->setX(10);
0228     dev->setY(-15);
0229 
0230     {
0231         KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
0232         int i = -1;
0233 
0234         while (it.nextPixel()) {
0235             i++;
0236             KoColor c(QColor(i % 255, i / 255, 0), colorSpace);
0237 
0238             memcpy(it.rawData(), c.data(), colorSpace->pixelSize());
0239         }
0240         QCOMPARE(dev->extent(), QRect(10, -15, 128, 192));
0241         QCOMPARE(dev->exactBounds(), QRect(10, 10, 128, 128));
0242     }
0243     {
0244         KisSequentialIterator it(dev, QRect(10, 10, 128, 128));
0245         QCOMPARE(it.rawData(), it.oldRawData());
0246     }
0247 }
0248 
0249 void KisIteratorNGTest::hLineIter(const KoColorSpace * colorSpace)
0250 {
0251     KisPaintDevice dev(colorSpace);
0252 
0253     QScopedArrayPointer<quint8> bytes(allocatePixels(colorSpace, 1));
0254 
0255     QCOMPARE(dev.extent(), QRect());
0256 
0257     KisHLineConstIteratorSP cit = dev.createHLineConstIteratorNG(0, 0, 128);
0258     while (!cit->nextPixel());
0259     QCOMPARE(dev.extent(), QRect());
0260     QCOMPARE(dev.exactBounds(), QRect(QPoint(0, 0), QPoint(-1, -1)));
0261 
0262     dev.clear();
0263     KisHLineIteratorSP it = dev.createHLineIteratorNG(0, 0, 128);
0264     do {
0265         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0266     } while (it->nextPixel());
0267 
0268 
0269     QCOMPARE(dev.extent(), QRect(0, 0, 128, 64));
0270     QCOMPARE(dev.exactBounds(), QRect(0, 0, 128, 1));
0271 
0272     dev.clear();
0273 
0274     it = dev.createHLineIteratorNG(0, 1, 128);
0275     do {
0276         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0277     } while (it->nextPixel());
0278 
0279     QCOMPARE(dev.extent(), QRect(0, 0, 128, 64));
0280     QCOMPARE(dev.exactBounds(), QRect(0, 1, 128, 1));
0281 
0282     dev.clear();
0283 
0284     it = dev.createHLineIteratorNG(10, 10, 128);
0285     do {
0286         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0287     } while (it->nextPixel());
0288 
0289     QCOMPARE(dev.extent(), QRect(0, 0, 192, 64));
0290     QCOMPARE(dev.exactBounds(), QRect(10, 10, 128, 1));
0291 
0292     dev.clear();
0293     dev.setX(10);
0294     dev.setY(-15);
0295 
0296     it = dev.createHLineIteratorNG(10, 10, 128);
0297     do {
0298         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0299     } while (it->nextPixel());
0300 
0301     QCOMPARE(dev.extent(), QRect(10, -15, 128, 64));
0302     QCOMPARE(dev.exactBounds(), QRect(10, 10, 128, 1));
0303     
0304     it = dev.createHLineIteratorNG(10, 10, 128);
0305     it->nextRow();
0306     QCOMPARE(it->rawData(), it->oldRawData());
0307 }
0308 
0309 void KisIteratorNGTest::justCreation(const KoColorSpace * colorSpace)
0310 {
0311     KisPaintDevice dev(colorSpace);
0312     dev.createVLineConstIteratorNG(0, 0, 128);
0313     dev.createVLineIteratorNG(0, 0, 128);
0314     dev.createHLineConstIteratorNG(0, 0, 128);
0315     dev.createHLineIteratorNG(0, 0, 128);
0316 }
0317 
0318 void KisIteratorNGTest::vLineIter(const KoColorSpace * colorSpace)
0319 {
0320 
0321     KisPaintDevice dev(colorSpace);
0322     QScopedArrayPointer<quint8> bytes(allocatePixels(colorSpace, 1));
0323 
0324     QCOMPARE(dev.extent(), QRect());
0325 
0326     KisVLineConstIteratorSP cit = dev.createVLineConstIteratorNG(0, 0, 128);
0327     while (cit->nextPixel());
0328     QCOMPARE(dev.extent(), QRect());
0329     QCOMPARE(dev.exactBounds(), QRect(QPoint(0, 0), QPoint(-1, -1)));
0330     cit.clear();
0331 
0332     KisVLineIteratorSP it = dev.createVLineIteratorNG(0, 0, 128);
0333     do {
0334         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0335     } while(it->nextPixel());
0336     
0337     QCOMPARE((QRect) dev.extent(), QRect(0, 0, 64, 128));
0338     QCOMPARE((QRect) dev.exactBounds(), QRect(0, 0, 1, 128));
0339     it.clear();
0340 
0341     dev.clear();
0342 
0343     it = dev.createVLineIteratorNG(10, 10, 128);
0344     do {
0345         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0346     } while(it->nextPixel());
0347 
0348     QCOMPARE(dev.extent(), QRect(0, 0, 64, 192));
0349     QCOMPARE(dev.exactBounds(), QRect(10, 10, 1, 128));
0350     
0351     dev.clear();
0352     dev.setX(10);
0353     dev.setY(-15);
0354 
0355     it = dev.createVLineIteratorNG(10, 10, 128);
0356     do {
0357         memcpy(it->rawData(), bytes.data(), colorSpace->pixelSize());
0358     } while(it->nextPixel());
0359 
0360     QCOMPARE(dev.extent(), QRect(10, -15, 64, 192));
0361     QCOMPARE(dev.exactBounds(), QRect(10, 10, 1, 128));
0362 
0363     it = dev.createVLineIteratorNG(10, 10, 128);
0364     it->nextColumn();
0365     QCOMPARE(it->rawData(), it->oldRawData());
0366 }
0367 
0368 void KisIteratorNGTest::randomAccessor(const KoColorSpace * colorSpace)
0369 {
0370 
0371     KisPaintDevice dev(colorSpace);
0372     QScopedArrayPointer<quint8> bytes(allocatePixels(colorSpace, 1));
0373 
0374     QCOMPARE(dev.extent(), QRect());
0375 
0376     KisRandomConstAccessorSP acc = dev.createRandomConstAccessorNG();
0377     for (int y = 0; y < 128; ++y) {
0378         for (int x = 0; x < 128; ++x) {
0379             acc->moveTo(x, y);
0380         }
0381     }
0382     QCOMPARE(dev.extent(), QRect());
0383 
0384     KisRandomAccessorSP ac = dev.createRandomAccessorNG();
0385     for (int y = 0; y < 128; ++y) {
0386         for (int x = 0; x < 128; ++x) {
0387             ac->moveTo(x, y);
0388             memcpy(ac->rawData(), bytes.data(), colorSpace->pixelSize());
0389         }
0390     }
0391     QCOMPARE(dev.extent(), QRect(0, 0, 128, 128));
0392     QCOMPARE(dev.exactBounds(), QRect(0, 0, 128, 128));
0393 
0394     dev.clear();
0395     dev.setX(10);
0396     dev.setY(-15);
0397 
0398     ac = dev.createRandomAccessorNG();
0399     for (int y = 0; y < 128; ++y) {
0400         for (int x = 0; x < 128; ++x) {
0401             ac->moveTo(x, y);
0402             memcpy(ac->rawData(), bytes.data(), colorSpace->pixelSize());
0403         }
0404     }
0405     QCOMPARE(dev.extent(), QRect(-54, -15, 192, 192));
0406     QCOMPARE(dev.exactBounds(), QRect(0, 0, 128, 128));
0407 }
0408 
0409 
0410 void KisIteratorNGTest::writeBytes()
0411 {
0412     allCsApplicator(&KisIteratorNGTest::writeBytes);
0413 }
0414 
0415 void KisIteratorNGTest::fill()
0416 {
0417     allCsApplicator(&KisIteratorNGTest::fill);
0418 }
0419 
0420 void KisIteratorNGTest::sequentialIter()
0421 {
0422     allCsApplicator(&KisIteratorNGTest::sequentialIter);
0423 }
0424 
0425 #include <KisSequentialIteratorProgress.h>
0426 
0427 void KisIteratorNGTest::sequentialIteratorWithProgress()
0428 {
0429     KisPaintDeviceSP dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
0430 
0431     const QRect rc(10,10,200,200);
0432     TestUtil::TestProgressBar proxy;
0433 
0434     KisSequentialConstIteratorProgress it (dev, rc, &proxy);
0435 
0436     while (it.nextPixel()) {
0437         QCOMPARE(proxy.min(), rc.top());
0438         QCOMPARE(proxy.max(), rc.top() + rc.height());
0439         QCOMPARE(proxy.value(), it.y());
0440     }
0441 
0442     QCOMPARE(proxy.max(), rc.top() + rc.height());
0443     QCOMPARE(proxy.value(), proxy.max());
0444 }
0445 
0446 void KisIteratorNGTest::sequentialIteratorWithProgressIncomplete()
0447 {
0448     KisPaintDeviceSP dev = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb8());
0449 
0450     const QRect rc(10,10,100,100);
0451     TestUtil::TestProgressBar proxy;
0452 
0453     {
0454         KisSequentialConstIteratorProgress it (dev, rc, &proxy);
0455 
0456         QCOMPARE(proxy.max(), rc.top() + rc.height());
0457         QCOMPARE(proxy.value(), rc.top());
0458     }
0459 
0460     // on destruction, iterator automatically completes progress reporting
0461     QCOMPARE(proxy.max(), rc.top() + rc.height());
0462     QCOMPARE(proxy.value(), proxy.max());
0463 }
0464 
0465 void KisIteratorNGTest::hLineIter()
0466 {
0467     allCsApplicator(&KisIteratorNGTest::hLineIter);
0468 }
0469 
0470 void KisIteratorNGTest::justCreation()
0471 {
0472     allCsApplicator(&KisIteratorNGTest::justCreation);
0473 }
0474 
0475 void KisIteratorNGTest::vLineIter()
0476 {
0477     allCsApplicator(&KisIteratorNGTest::vLineIter);
0478 }
0479 
0480 void KisIteratorNGTest::randomAccessor()
0481 {
0482     allCsApplicator(&KisIteratorNGTest::randomAccessor);
0483 }
0484 
0485 KISTEST_MAIN(KisIteratorNGTest)