Warning, file /graphics/krita/sdk/tests/stroke_testing_utils.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  *  SPDX-FileCopyrightText: 2011 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "stroke_testing_utils.h"
0008 
0009 #include <simpletest.h>
0010 
0011 #include <QDir>
0012 #include <KoColor.h>
0013 #include <KoColorSpace.h>
0014 #include <KoColorSpaceRegistry.h>
0015 #include <KoCompositeOpRegistry.h>
0016 #include <brushengine/kis_paintop_preset.h>
0017 #include <resources/KoPattern.h>
0018 #include "kis_canvas_resource_provider.h"
0019 #include "kis_image.h"
0020 #include "kis_paint_device.h"
0021 #include "kis_paint_layer.h"
0022 #include "kis_group_layer.h"
0023 #include <KisViewManager.h>
0024 
0025 #include <testutil.h>
0026 #include <KisGlobalResourcesInterface.h>
0027 
0028 
0029 KisImageSP utils::createImage(KisUndoStore *undoStore, const QSize &imageSize) {
0030     QRect imageRect(0,0,imageSize.width(),imageSize.height());
0031 
0032     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
0033     KisImageSP image = new KisImage(undoStore, imageRect.width(), imageRect.height(), cs, "stroke test");
0034 
0035     KisPaintLayerSP paintLayer1 = new KisPaintLayer(image, "paint1", OPACITY_OPAQUE_U8);
0036     KisPaintLayerSP paintLayer2 = new KisPaintLayer(image, "paint2", OPACITY_OPAQUE_U8);
0037     KisPaintLayerSP paintLayer3 = new KisPaintLayer(image, "paint3", OPACITY_OPAQUE_U8);
0038     KisPaintLayerSP paintLayer4 = new KisPaintLayer(image, "paint4", OPACITY_OPAQUE_U8);
0039     KisPaintLayerSP paintLayer5 = new KisPaintLayer(image, "paint5", OPACITY_OPAQUE_U8);
0040 
0041     image->barrierLock();
0042     image->addNode(paintLayer1);
0043     image->addNode(paintLayer2);
0044     image->addNode(paintLayer3);
0045     image->addNode(paintLayer4);
0046     image->addNode(paintLayer5);
0047     image->unlock();
0048     return image;
0049 }
0050 
0051 KoCanvasResourceProvider* utils::createResourceManager(KisImageWSP image,
0052                                                 KisNodeSP node,
0053                                                 const QString &presetFileName)
0054 {
0055     KoCanvasResourceProvider *manager = new KoCanvasResourceProvider();
0056     KisViewManager::initializeResourceManager(manager);
0057 
0058     QVariant i;
0059 
0060     i.setValue(KoColor(Qt::black, image->colorSpace()));
0061     manager->setResource(KoCanvasResource::ForegroundColor, i);
0062 
0063     i.setValue(KoColor(Qt::white, image->colorSpace()));
0064     manager->setResource(KoCanvasResource::BackgroundColor, i);
0065 
0066     i.setValue(static_cast<void*>(0));
0067     manager->setResource(KoCanvasResource::CurrentPattern, i);
0068     manager->setResource(KoCanvasResource::CurrentGradient, i);
0069     manager->setResource(KoCanvasResource::CurrentGeneratorConfiguration, i);
0070 
0071     if(!node) {
0072         node = image->root();
0073 
0074         while(node && !dynamic_cast<KisPaintLayer*>(node.data())) {
0075             node = node->firstChild();
0076         }
0077 
0078         Q_ASSERT(node && dynamic_cast<KisPaintLayer*>(node.data()));
0079     }
0080 
0081     i.setValue(node);
0082     manager->setResource(KoCanvasResource::CurrentKritaNode, i);
0083 
0084     KisPaintOpPresetSP preset;
0085 
0086     if (!presetFileName.isEmpty()) {
0087         QString fullFileName = TestUtil::fetchDataFileLazy(presetFileName);
0088         preset = KisPaintOpPresetSP(new KisPaintOpPreset(fullFileName));
0089         bool presetValid = preset->load(KisGlobalResourcesInterface::instance());
0090         Q_ASSERT(presetValid); Q_UNUSED(presetValid);
0091 
0092         i.setValue(preset);
0093         manager->setResource(KoCanvasResource::CurrentPaintOpPreset, i);
0094     }
0095 
0096     i.setValue(COMPOSITE_OVER);
0097     manager->setResource(KoCanvasResource::CurrentCompositeOp, i);
0098 
0099     i.setValue(false);
0100     manager->setResource(KoCanvasResource::MirrorHorizontal, i);
0101 
0102     i.setValue(false);
0103     manager->setResource(KoCanvasResource::MirrorVertical, i);
0104 
0105     i.setValue(1.0);
0106     manager->setResource(KoCanvasResource::Opacity, i);
0107 
0108     i.setValue(1.0);
0109     manager->setResource(KoCanvasResource::HdrExposure, i);
0110 
0111     return manager;
0112 }
0113 
0114 utils::StrokeTester::StrokeTester(const QString &name, const QSize &imageSize, const QString &presetFilename)
0115     : m_name(name),
0116       m_imageSize(imageSize),
0117       m_presetFilename(presetFilename),
0118       m_numIterations(1),
0119       m_baseFuzziness(1)
0120 {
0121 }
0122 
0123 utils::StrokeTester::~StrokeTester()
0124 {
0125 }
0126 
0127 void utils::StrokeTester::setNumIterations(int value)
0128 {
0129     m_numIterations = value;
0130 }
0131 
0132 void utils::StrokeTester::setBaseFuzziness(int value)
0133 {
0134     m_baseFuzziness = value;
0135 }
0136 
0137 void utils::StrokeTester::testSimpleStroke()
0138 {
0139     testOneStroke(false, true, false, true);
0140 }
0141 
0142 int utils::StrokeTester::lastStrokeTime() const
0143 {
0144     return m_strokeTime;
0145 }
0146 
0147 void utils::StrokeTester::test()
0148 {
0149     testOneStroke(false, false, false);
0150     testOneStroke(false, true, false);
0151     testOneStroke(true, false, false);
0152     testOneStroke(true, true, false);
0153 
0154     // The same but with updates (compare against projection)
0155 
0156     testOneStroke(false, false, false, true);
0157     testOneStroke(false, true, false, true);
0158     testOneStroke(true, false, false, true);
0159     testOneStroke(true, true, false, true);
0160 
0161     // The same, but with an external layer
0162 
0163     testOneStroke(false, false, true);
0164     testOneStroke(false, true, true);
0165     testOneStroke(true, false, true);
0166     testOneStroke(true, true, true);
0167 }
0168 
0169 void utils::StrokeTester::benchmark()
0170 {
0171     // not cancelled, indirect painting, internal, no updates, no qimage
0172     doStroke(false, false, false, false);
0173 }
0174 
0175 void utils::StrokeTester::testSimpleStrokeNoVerification()
0176 {
0177     doStroke(false, false, true, false);
0178 }
0179 
0180 void utils::StrokeTester::testOneStroke(bool cancelled,
0181                                         bool indirectPainting,
0182                                         bool externalLayer,
0183                                         bool testUpdates)
0184 {
0185     // TODO: indirectPainting option is not used anymore! The real value is
0186     //       taken from the preset!
0187 
0188     QString testName = formatTestName(m_name,
0189                                       cancelled,
0190                                       indirectPainting,
0191                                       externalLayer);
0192 
0193     dbgKrita << "Testcase:" << testName
0194              << "(compare against " << (testUpdates ? "projection" : "layer") << ")";
0195 
0196     QImage resultImage;
0197     resultImage = doStroke(cancelled, externalLayer, testUpdates);
0198 
0199     QImage refImage;
0200     refImage.load(referenceFile(testName));
0201 
0202     QPoint temp;
0203     if(!TestUtil::compareQImages(temp, refImage, resultImage, m_baseFuzziness, m_baseFuzziness)) {
0204         refImage.save(dumpReferenceFile(testName));
0205         resultImage.save(resultFile(testName));
0206 
0207         QFAIL("Images do not coincide");
0208     }
0209 }
0210 
0211 QString utils::StrokeTester::formatTestName(const QString &baseName,
0212                                             bool cancelled,
0213                                             bool indirectPainting,
0214                                             bool externalLayer)
0215 {
0216     QString result = baseName;
0217     result += "_" + m_presetFilename;
0218     result += indirectPainting ? "_indirect" : "_incremental";
0219     result += cancelled ? "_cancelled" : "_finished";
0220     result += externalLayer ? "_external" : "_internal";
0221     return result;
0222 }
0223 
0224 QString utils::StrokeTester::referenceFile(const QString &testName)
0225 {
0226     QString path =
0227         QString(FILES_DATA_DIR) + '/' +
0228         m_name + '/';
0229 
0230     path += testName;
0231     path += ".png";
0232     return path;
0233 }
0234 
0235 QString utils::StrokeTester::dumpReferenceFile(const QString &testName)
0236 {
0237     QString path = QString(FILES_OUTPUT_DIR) + '/';
0238     path += testName;
0239     path += "_expected";
0240     path += ".png";
0241     return path;
0242 }
0243 
0244 QString utils::StrokeTester::resultFile(const QString &testName)
0245 {
0246     QString path = QString(FILES_OUTPUT_DIR) + '/';
0247     path += testName;
0248     path += ".png";
0249     return path;
0250 }
0251 
0252 QImage utils::StrokeTester::doStroke(bool cancelled,
0253                                      bool externalLayer,
0254                                      bool testUpdates,
0255                                      bool needQImage)
0256 {
0257     KisImageSP image = utils::createImage(0, m_imageSize);
0258     KoCanvasResourceProvider *manager = utils::createResourceManager(image, 0, m_presetFilename);
0259     KisNodeSP currentNode;
0260 
0261     for (int i = 0; i < m_numIterations; i++) {
0262         modifyResourceManager(manager, image, i);
0263 
0264         KisResourcesSnapshotSP resources =
0265             new KisResourcesSnapshot(image,
0266                                      image->rootLayer()->firstChild(),
0267                                      manager);
0268 
0269         if(externalLayer) {
0270             KisNodeSP externalNode = new KisPaintLayer(0, "extlyr", OPACITY_OPAQUE_U8, image->colorSpace());
0271             resources->setCurrentNode(externalNode);
0272             Q_ASSERT(resources->currentNode() == externalNode);
0273         }
0274 
0275         initImage(image, resources->currentNode(), i);
0276 
0277         QElapsedTimer strokeTime;
0278         strokeTime.start();
0279 
0280         KisStrokeStrategy *stroke = createStroke(resources, image);
0281         m_strokeId = image->startStroke(stroke);
0282         addPaintingJobs(image, resources, i);
0283 
0284         if(!cancelled) {
0285             image->endStroke(m_strokeId);
0286         }
0287         else {
0288             image->cancelStroke(m_strokeId);
0289         }
0290 
0291         image->waitForDone();
0292 
0293         m_strokeTime = strokeTime.elapsed();
0294         currentNode = resources->currentNode();
0295     }
0296 
0297     beforeCheckingResult(image, currentNode);
0298 
0299     QImage resultImage;
0300     if(needQImage) {
0301         KisPaintDeviceSP device = testUpdates ?
0302             image->projection() :
0303             currentNode->paintDevice();
0304 
0305         resultImage = device->convertToQImage(0, 0, 0, image->width(), image->height());
0306     }
0307 
0308     image = 0;
0309     delete manager;
0310     return resultImage;
0311 }
0312 
0313 void utils::StrokeTester::modifyResourceManager(KoCanvasResourceProvider *manager,
0314                                                 KisImageWSP image, int iteration)
0315 {
0316     Q_UNUSED(iteration);
0317     modifyResourceManager(manager, image);
0318 }
0319 
0320 void utils::StrokeTester::modifyResourceManager(KoCanvasResourceProvider *manager,
0321                                                 KisImageWSP image)
0322 {
0323     Q_UNUSED(manager);
0324     Q_UNUSED(image);
0325 }
0326 
0327 void utils::StrokeTester::initImage(KisImageWSP image, KisNodeSP activeNode, int iteration)
0328 {
0329     Q_UNUSED(iteration);
0330     initImage(image, activeNode);
0331 }
0332 
0333 void utils::StrokeTester::initImage(KisImageWSP image, KisNodeSP activeNode)
0334 {
0335     Q_UNUSED(image);
0336     Q_UNUSED(activeNode);
0337 }
0338 
0339 void utils::StrokeTester::addPaintingJobs(KisImageWSP image,
0340                                           KisResourcesSnapshotSP resources,
0341                                           int iteration)
0342 {
0343     Q_UNUSED(iteration);
0344     addPaintingJobs(image, resources);
0345 }
0346 
0347 void utils::StrokeTester::addPaintingJobs(KisImageWSP image,
0348                                           KisResourcesSnapshotSP resources)
0349 {
0350     Q_UNUSED(image);
0351     Q_UNUSED(resources);
0352 }
0353 
0354 void utils::StrokeTester::beforeCheckingResult(KisImageWSP image, KisNodeSP activeNode)
0355 {
0356     Q_UNUSED(image);
0357     Q_UNUSED(activeNode);
0358 }