#include "AddressSpaceLimit.h" #include "Document/Filters.h" #include "Document/PixelAdjust.h" #include "IO/ImageExporter.h" #include #include #include // The filters' pixels when memory runs out. class FilterFailureTests : public QObject { Q_OBJECT private slots: void theBlursFailAsAContextWhenTheirRowsFindNoMemory(); void aTrimThatFindsNoMemoryIsARenderError(); void aDitherThatFindsNoMemoryIsARenderError(); }; void FilterFailureTests::theBlursFailAsAContextWhenTheirRowsFindNoMemory() { // One pixel wide: its row list asks as its pixels. QImage tall(1, 16'000'000, QImage::Format_RGBA8888_Premultiplied); tall.fill(Qt::red); malloc_trim(0); { // The 64 MB result fits; the rows do not. const AddressSpaceLimit limit(80ll * 1024 * 1024); QVERIFY_THROWS_EXCEPTION(ExportError, PixelAdjust::motionBlur(tall, 1, 0)); } malloc_trim(0); { // Result and 256 MB of sums fit; rows do not. const AddressSpaceLimit limit(350ll * 1024 * 1024); QVERIFY_THROWS_EXCEPTION(ExportError, PixelAdjust::gaussianBlur(tall, 1, false)); } } void FilterFailureTests::aTrimThatFindsNoMemoryIsARenderError() { // Opaque but for its border: the crop copies 96 MB. QImage framed(6000, 4000, QImage::Format_RGBA8888_Premultiplied); framed.fill(Qt::transparent); QPainter(&framed).fillRect(QRect(1, 1, 5998, 3998), Qt::red); malloc_trim(0); const AddressSpaceLimit limit(16ll * 1024 * 1024); QVERIFY_THROWS_EXCEPTION(ExportError, PixelFilter::trimmed(framed, LayerTransform{.origin = {0, 0}, .size = {6000, 4000}})); } void FilterFailureTests::aDitherThatFindsNoMemoryIsARenderError() { // Qt 6.10 converts on threads the limit starves first. if (!placesStarvation()) QSKIP("the failure point is placed for Qt 6.4's allocations"); DitherSettings dither; dither.pixelSize = 1; // Another format: its conversion finds no memory. QImage plain(4000, 4000, QImage::Format_RGB32); plain.fill(Qt::gray); malloc_trim(0); { const AddressSpaceLimit limit(16ll * 1024 * 1024); QVERIFY_THROWS_EXCEPTION(ExportError, dither.apply(plain)); } // The 64 MB copy fits; the kernel's planes do not. const QImage premultiplied = plain.convertToFormat(QImage::Format_RGBA8888_Premultiplied); plain = QImage(); malloc_trim(0); { const AddressSpaceLimit limit(96ll * 1024 * 1024); QVERIFY_THROWS_EXCEPTION(ExportError, dither.apply(premultiplied)); } // Chunky pixels dither a small copy: the same limit holds. dither.pixelSize = 8; dither.colors = DitherColors::original; malloc_trim(0); { const AddressSpaceLimit limit(96ll * 1024 * 1024); QCOMPARE(dither.apply(premultiplied).size(), QSize(4000, 4000)); } } QTEST_GUILESS_MAIN(FilterFailureTests) #include "FilterFailureTests.moc"