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

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_layer_style_projection_plane_test.h"
0008 
0009 #include <simpletest.h>
0010 
0011 #include <testutil.h>
0012 #include <testimage.h>
0013 
0014 #include <KoColor.h>
0015 #include <KoColorSpace.h>
0016 #include <KoColorSpaceRegistry.h>
0017 #include <resources/KoPattern.h>
0018 
0019 #include "kis_transparency_mask.h"
0020 #include "kis_paint_layer.h"
0021 #include "kis_image.h"
0022 #include "kis_painter.h"
0023 
0024 #include "kis_selection.h"
0025 #include "kis_pixel_selection.h"
0026 
0027 #include "layerstyles/kis_layer_style_projection_plane.h"
0028 #include "kis_psd_layer_style.h"
0029 #include "kis_paint_device_debug_utils.h"
0030 #include <KisGlobalResourcesInterface.h>
0031 #include <KisLocalStrokeResources.h>
0032 
0033 
0034 void KisLayerStyleProjectionPlaneTest::test(KisPSDLayerStyleSP style, const QString testName)
0035 {
0036     const QRect imageRect(0, 0, 200, 200);
0037     const QRect rFillRect(10, 10, 100, 100);
0038     const QRect tMaskRect(50, 50, 20, 20);
0039     const QRect partialSelectionRect(90, 50, 20, 20);
0040 
0041     const QRect updateRect1(10, 10, 50, 100);
0042     const QRect updateRect2(60, 10, 50, 100);
0043 
0044     const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8();
0045     KisImageSP image = new KisImage(0, imageRect.width(), imageRect.height(), cs, "styles test");
0046 
0047     KisPaintLayerSP layer = new KisPaintLayer(image, "test", OPACITY_OPAQUE_U8);
0048     image->addNode(layer);
0049 
0050     KisLayerStyleProjectionPlane plane(layer.data(), style);
0051 
0052     KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "00L_initial", testName);
0053 
0054     //layer->paintDevice()->fill(rFillRect, KoColor(Qt::red, cs));
0055     {
0056         KisPainter gc(layer->paintDevice());
0057         gc.setPaintColor(KoColor(Qt::red, cs));
0058         gc.setFillStyle(KisPainter::FillStyleForegroundColor);
0059         gc.paintEllipse(rFillRect);
0060     }
0061 
0062     KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "01L_fill", testName);
0063 
0064     KisPaintDeviceSP projection = new KisPaintDevice(cs);
0065 
0066     {
0067         projection->clear();
0068         const QRect changeRect = plane.changeRect(rFillRect, KisLayer::N_FILTHY);
0069         dbgKrita << ppVar(rFillRect) << ppVar(changeRect);
0070 
0071         plane.recalculate(changeRect, layer);
0072 
0073         KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "02L_recalculate_fill", testName);
0074 
0075         KisPainter painter(projection);
0076         plane.apply(&painter, changeRect);
0077 
0078         KIS_DUMP_DEVICE_2(projection, imageRect, "03P_apply_on_fill", testName);
0079     }
0080 
0081     {
0082         KisNodeSP clonedNode = layer->clone();
0083         KisLayerSP clonedLayer = dynamic_cast<KisLayer*>(layer.data());
0084 
0085         KisLayerStyleProjectionPlaneSP clonedPlane =
0086             toQShared(new KisLayerStyleProjectionPlane(plane,
0087                                                        clonedLayer.data(),
0088                                                        style));
0089 
0090         const QRect changeRect = clonedPlane->changeRect(rFillRect, KisLayer::N_FILTHY);
0091         dbgKrita << ppVar(rFillRect) << ppVar(changeRect);
0092 
0093         KIS_DUMP_DEVICE_2(clonedLayer->projection(), imageRect, "04L_clone_state_after_copy", testName);
0094 
0095         {
0096             projection->clear();
0097             KisPainter painter(projection);
0098             clonedPlane->apply(&painter, changeRect);
0099 
0100             KIS_DUMP_DEVICE_2(projection, imageRect, "05P_apply_clone_after_copy", testName);
0101         }
0102 
0103         clonedPlane->recalculate(changeRect, clonedLayer);
0104 
0105         KIS_DUMP_DEVICE_2(clonedLayer->projection(), imageRect, "06L_recalculate_clone", testName);
0106 
0107         {
0108             projection->clear();
0109             KisPainter painter(projection);
0110             clonedPlane->apply(&painter, changeRect);
0111 
0112             KIS_DUMP_DEVICE_2(projection, imageRect, "07P_apply_recalculated_clone", testName);
0113         }
0114     }
0115 
0116     //return;
0117 
0118     KisTransparencyMaskSP transparencyMask = new KisTransparencyMask(image, "tmask");
0119 
0120     KisSelectionSP selection = new KisSelection();
0121     selection->pixelSelection()->select(tMaskRect, OPACITY_OPAQUE_U8);
0122     transparencyMask->setSelection(selection);
0123     image->addNode(transparencyMask, layer);
0124 
0125     KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "08L_mask_added", testName);
0126 
0127     plane.recalculate(imageRect, layer);
0128 
0129     KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "09_mask_added_recalculated", testName);
0130 
0131     {
0132         projection->clear();
0133 
0134         KisPainter painter(projection);
0135         plane.apply(&painter, imageRect);
0136 
0137         KIS_DUMP_DEVICE_2(projection, imageRect, "10P_apply_on_mask", testName);
0138     }
0139 
0140     selection->pixelSelection()->select(partialSelectionRect, OPACITY_OPAQUE_U8);
0141 
0142     {
0143         const QRect changeRect = plane.changeRect(partialSelectionRect, KisLayer::N_FILTHY);
0144         projection->clear(changeRect);
0145 
0146         dbgKrita << ppVar(partialSelectionRect) << ppVar(changeRect);
0147 
0148         plane.recalculate(changeRect, layer);
0149 
0150         KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "11L_recalculate_partial", testName);
0151 
0152         KisPainter painter(projection);
0153         plane.apply(&painter, changeRect);
0154 
0155         KIS_DUMP_DEVICE_2(projection, imageRect, "12P_apply_partial", testName);
0156     }
0157 
0158     // half updates
0159     transparencyMask->setVisible(false);
0160 
0161     {
0162         const QRect changeRect = plane.changeRect(updateRect1, KisLayer::N_FILTHY);
0163         projection->clear(changeRect);
0164 
0165         dbgKrita << ppVar(updateRect1) << ppVar(changeRect);
0166 
0167         plane.recalculate(changeRect, layer);
0168 
0169         KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "13recalculate_half1", testName);
0170 
0171         KisPainter painter(projection);
0172         plane.apply(&painter, changeRect);
0173 
0174         KIS_DUMP_DEVICE_2(projection, imageRect, "14P_apply_half1", testName);
0175     }
0176 
0177     {
0178         const QRect changeRect = plane.changeRect(updateRect2, KisLayer::N_FILTHY);
0179         projection->clear(changeRect);
0180 
0181         dbgKrita << ppVar(updateRect2) << ppVar(changeRect);
0182 
0183         plane.recalculate(changeRect, layer);
0184 
0185         KIS_DUMP_DEVICE_2(layer->projection(), imageRect, "15L_recalculate_half1", testName);
0186 
0187         KisPainter painter(projection);
0188         plane.apply(&painter, changeRect);
0189 
0190         KIS_DUMP_DEVICE_2(projection, imageRect, "16P_apply_half2", testName);
0191     }
0192 }
0193 
0194 
0195 void KisLayerStyleProjectionPlaneTest::testShadow()
0196 {
0197     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0198     style->dropShadow()->setSize(15);
0199     style->dropShadow()->setDistance(15);
0200     style->dropShadow()->setOpacity(70);
0201     style->dropShadow()->setNoise(30);
0202     style->dropShadow()->setEffectEnabled(true);
0203 
0204     style->innerShadow()->setSize(10);
0205     style->innerShadow()->setSpread(10);
0206     style->innerShadow()->setDistance(5);
0207     style->innerShadow()->setOpacity(70);
0208     style->innerShadow()->setNoise(30);
0209     style->innerShadow()->setEffectEnabled(true);
0210 
0211     test(style, "shadow");
0212 }
0213 
0214 void KisLayerStyleProjectionPlaneTest::testGlow()
0215 {
0216     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0217     style->outerGlow()->setSize(15);
0218     style->outerGlow()->setSpread(10);
0219     style->outerGlow()->setOpacity(70);
0220     style->outerGlow()->setNoise(30);
0221     style->outerGlow()->setEffectEnabled(true);
0222     style->outerGlow()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='0.0' g='1.0' b='0.0'/></color>"));
0223 
0224     test(style, "glow_outer");
0225 }
0226 
0227 #include <resources/KoStopGradient.h>
0228 
0229 void KisLayerStyleProjectionPlaneTest::testGlowGradient()
0230 {
0231     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0232     style->outerGlow()->setSize(15);
0233     style->outerGlow()->setSpread(10);
0234     style->outerGlow()->setOpacity(70);
0235     style->outerGlow()->setNoise(10);
0236     style->outerGlow()->setEffectEnabled(true);
0237     style->outerGlow()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='0.0' g='1.0' b='0.0'/></color>"));
0238 
0239     QLinearGradient testGradient;
0240     testGradient.setColorAt(0.0, Qt::white);
0241     testGradient.setColorAt(0.5, Qt::green);
0242     testGradient.setColorAt(1.0, Qt::black);
0243     testGradient.setSpread(QGradient::ReflectSpread);
0244     QSharedPointer<KoStopGradient> gradient(
0245         KoStopGradient::fromQGradient(&testGradient));
0246 
0247     style->outerGlow()->setGradient(gradient);
0248     style->outerGlow()->setFillType(psd_fill_gradient);
0249 
0250     test(style, "glow_outer_grad");
0251 }
0252 
0253 void KisLayerStyleProjectionPlaneTest::testGlowGradientJitter()
0254 {
0255     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0256     style->outerGlow()->setSize(15);
0257     style->outerGlow()->setSpread(10);
0258     style->outerGlow()->setOpacity(70);
0259     style->outerGlow()->setNoise(0);
0260     style->outerGlow()->setEffectEnabled(true);
0261     style->outerGlow()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='0.0' g='1.0' b='0.0'/></color>"));
0262 
0263     QLinearGradient testGradient;
0264     testGradient.setColorAt(0.0, Qt::white);
0265     testGradient.setColorAt(0.5, Qt::green);
0266     testGradient.setColorAt(1.0, Qt::black);
0267     testGradient.setSpread(QGradient::ReflectSpread);
0268     QSharedPointer<KoStopGradient> gradient(
0269         KoStopGradient::fromQGradient(&testGradient));
0270 
0271     style->outerGlow()->setGradient(gradient);
0272     style->outerGlow()->setFillType(psd_fill_gradient);
0273     style->outerGlow()->setJitter(20);
0274 
0275 
0276 
0277     test(style, "glow_outer_grad_jit");
0278 }
0279 
0280 void KisLayerStyleProjectionPlaneTest::testGlowInnerGradient()
0281 {
0282     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0283     style->innerGlow()->setSize(15);
0284     style->innerGlow()->setSpread(10);
0285     style->innerGlow()->setOpacity(80);
0286     style->innerGlow()->setNoise(10);
0287     style->innerGlow()->setEffectEnabled(true);
0288     style->innerGlow()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='1.0' b='1.0'/></color>"));
0289 
0290     QLinearGradient testGradient;
0291     testGradient.setColorAt(0.0, Qt::white);
0292     testGradient.setColorAt(0.5, Qt::green);
0293     testGradient.setColorAt(1.0, Qt::black);
0294     testGradient.setSpread(QGradient::ReflectSpread);
0295     QSharedPointer<KoStopGradient> gradient(
0296         KoStopGradient::fromQGradient(&testGradient));
0297 
0298     style->innerGlow()->setGradient(gradient);
0299     style->innerGlow()->setFillType(psd_fill_gradient);
0300 
0301     test(style, "glow_inner_grad");
0302 
0303     style->innerGlow()->setFillType(psd_fill_solid_color);
0304     style->innerGlow()->setSource(psd_glow_center);
0305     test(style, "glow_inner_grad_center");
0306 }
0307 
0308 #include <KoCompositeOpRegistry.h>
0309 
0310 
0311 void KisLayerStyleProjectionPlaneTest::testSatin()
0312 {
0313     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0314     style->satin()->setSize(15);
0315     style->satin()->setOpacity(80);
0316     style->satin()->setAngle(180);
0317     style->satin()->setEffectEnabled(true);
0318     style->satin()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='1.0' b='1.0'/></color>"));
0319     style->satin()->setBlendMode(COMPOSITE_LINEAR_DODGE);
0320 
0321     test(style, "satin");
0322 }
0323 
0324 void KisLayerStyleProjectionPlaneTest::testColorOverlay()
0325 {
0326     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0327     style->colorOverlay()->setOpacity(80);
0328     style->colorOverlay()->setEffectEnabled(true);
0329     style->colorOverlay()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='1.0' b='1.0'/></color>"));
0330     style->colorOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE);
0331 
0332     test(style, "color_overlay");
0333 }
0334 
0335 void KisLayerStyleProjectionPlaneTest::testGradientOverlay()
0336 {
0337     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0338     style->gradientOverlay()->setAngle(90);
0339     style->gradientOverlay()->setOpacity(80);
0340     style->gradientOverlay()->setEffectEnabled(true);
0341     style->gradientOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE);
0342     style->gradientOverlay()->setAlignWithLayer(true);
0343     style->gradientOverlay()->setScale(100);
0344     style->gradientOverlay()->setStyle(psd_gradient_style_diamond);
0345 
0346     QLinearGradient testGradient;
0347     testGradient.setColorAt(0.0, Qt::white);
0348     testGradient.setColorAt(0.5, Qt::green);
0349     testGradient.setColorAt(1.0, Qt::black);
0350     testGradient.setSpread(QGradient::ReflectSpread);
0351     QSharedPointer<KoStopGradient> gradient(
0352         KoStopGradient::fromQGradient(&testGradient));
0353 
0354     style->gradientOverlay()->setGradient(gradient);
0355 
0356     test(style, "grad_overlay");
0357 }
0358 
0359 void KisLayerStyleProjectionPlaneTest::testPatternOverlay()
0360 {
0361     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0362     style->patternOverlay()->setOpacity(80);
0363     style->patternOverlay()->setEffectEnabled(true);
0364     style->patternOverlay()->setBlendMode(COMPOSITE_LINEAR_DODGE);
0365     style->patternOverlay()->setScale(100);
0366 
0367     style->patternOverlay()->setAlignWithLayer(false);
0368 
0369     QString fileName(TestUtil::fetchDataFileLazy("pattern.pat"));
0370 
0371     KoPatternSP pattern(new KoPattern(fileName));
0372 
0373     QVERIFY(pattern->load(KisGlobalResourcesInterface::instance()));
0374 
0375 
0376     QSharedPointer<KisLocalStrokeResources> resourcesInterface(new KisLocalStrokeResources());
0377     resourcesInterface->addResource(pattern);
0378     style->setResourcesInterface(resourcesInterface);
0379 
0380     style->patternOverlay()->setPattern(pattern);
0381 
0382     test(style, "pat_overlay");
0383 }
0384 
0385 void KisLayerStyleProjectionPlaneTest::testStroke()
0386 {
0387     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0388     style->stroke()->setColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='0.0' g='0.0' b='1.0'/></color>"));
0389     style->stroke()->setOpacity(80);
0390     style->stroke()->setEffectEnabled(true);
0391     style->stroke()->setBlendMode(COMPOSITE_OVER);
0392 
0393     style->stroke()->setSize(3);
0394     style->stroke()->setPosition(psd_stroke_center);
0395 
0396     test(style, "stroke_col_ctr");
0397 
0398     style->stroke()->setPosition(psd_stroke_outside);
0399 
0400     test(style, "stroke_col_out");
0401 
0402     style->stroke()->setPosition(psd_stroke_inside);
0403 
0404     test(style, "stroke_col_in");
0405 
0406 
0407     QString fileName(TestUtil::fetchDataFileLazy("pattern.pat"));
0408     KoPatternSP pattern(new KoPattern(fileName));
0409     QVERIFY(pattern->load(KisGlobalResourcesInterface::instance()));
0410 
0411     QSharedPointer<KisLocalStrokeResources> resourcesInterface(new KisLocalStrokeResources());
0412     resourcesInterface->addResource(pattern);
0413     style->setResourcesInterface(resourcesInterface);
0414 
0415     style->stroke()->setPattern(pattern);
0416     style->stroke()->setFillType(psd_fill_pattern);
0417 
0418     test(style, "stroke_pat");
0419 
0420 
0421     QLinearGradient testGradient;
0422     testGradient.setColorAt(0.0, Qt::white);
0423     testGradient.setColorAt(0.5, Qt::green);
0424     testGradient.setColorAt(1.0, Qt::black);
0425     testGradient.setSpread(QGradient::ReflectSpread);
0426     QSharedPointer<KoStopGradient> gradient(
0427         KoStopGradient::fromQGradient(&testGradient));
0428 
0429     style->stroke()->setGradient(gradient);
0430     style->stroke()->setFillType(psd_fill_gradient);
0431 
0432     test(style, "stroke_grad");
0433 
0434 }
0435 
0436 #include "layerstyles/gimp_bump_map.h"
0437 
0438 void KisLayerStyleProjectionPlaneTest::testBumpmap()
0439 {
0440     KisPixelSelectionSP device = new KisPixelSelection();
0441 
0442     const int numCycles = 30;
0443     const int step = 5;
0444 
0445     QRect applyRect(200, 100, 100, 100);
0446     QRect fillRect(210, 110, 80, 80);
0447     quint8 selectedness = 256 - numCycles * step;
0448 
0449 
0450     for (int i = 0; i < numCycles; i++) {
0451         device->select(fillRect, selectedness);
0452 
0453         fillRect = kisGrowRect(fillRect, -1);
0454         selectedness += step;
0455     }
0456 
0457     KIS_DUMP_DEVICE_2(device, applyRect, "00_initial", "bumpmap");
0458 
0459 
0460     bumpmap_vals_t bmvals;
0461 
0462     bmvals.azimuth = 240;
0463     bmvals.elevation = 30;
0464     bmvals.depth = 50;
0465     bmvals.ambient = 128;
0466     bmvals.compensate = false;
0467     bmvals.invert = false;
0468     bmvals.type = 0;
0469 
0470     bumpmap(device, applyRect, bmvals);
0471 
0472     KIS_DUMP_DEVICE_2(device, applyRect, "01_bumpmapped", "bumpmap");
0473 
0474 }
0475 
0476 void KisLayerStyleProjectionPlaneTest::testBevel()
0477 {
0478     KisPSDLayerStyleSP style(new KisPSDLayerStyle());
0479     style->bevelAndEmboss()->setEffectEnabled(true);
0480 
0481     style->bevelAndEmboss()->setAngle(135);
0482     style->bevelAndEmboss()->setAltitude(45);
0483     style->bevelAndEmboss()->setDepth(100);
0484 
0485     style->bevelAndEmboss()->setHighlightColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='1.0' g='1.0' b='1.0'/></color>"));
0486     style->bevelAndEmboss()->setHighlightBlendMode(COMPOSITE_OVER);
0487     style->bevelAndEmboss()->setHighlightOpacity(100);
0488 
0489     style->bevelAndEmboss()->setShadowColor(KoColor::fromXML("<color channeldepth='U8'><sRGB r='0.0' g='0.0' b='0.0'/></color>"));
0490     style->bevelAndEmboss()->setShadowBlendMode(COMPOSITE_OVER);
0491     style->bevelAndEmboss()->setShadowOpacity(100);
0492 
0493     QString fileName(TestUtil::fetchDataFileLazy("pattern.pat"));
0494     KoPatternSP pattern(new KoPattern(fileName));
0495     QVERIFY(pattern->load(KisGlobalResourcesInterface::instance()));
0496     Q_ASSERT(!pattern->md5Sum().isEmpty());
0497     QSharedPointer<KisLocalStrokeResources> resourcesInterface(new KisLocalStrokeResources());
0498     resourcesInterface->addResource(pattern);
0499 
0500     style->setResourcesInterface(resourcesInterface);
0501     style->bevelAndEmboss()->setTexturePattern(pattern);
0502 
0503     style->bevelAndEmboss()->setTextureEnabled(true);
0504     style->bevelAndEmboss()->setTextureDepth(-10);
0505     style->bevelAndEmboss()->setTextureInvert(false);
0506 
0507     style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel);
0508     style->bevelAndEmboss()->setDirection(psd_direction_up);
0509     style->bevelAndEmboss()->setSoften(0);
0510     test(style, "bevel_outer_up");
0511 
0512     style->bevelAndEmboss()->setTextureInvert(true);
0513     style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel);
0514     style->bevelAndEmboss()->setDirection(psd_direction_up);
0515     style->bevelAndEmboss()->setSoften(0);
0516     test(style, "bevel_outer_up_invert_texture");
0517     style->bevelAndEmboss()->setTextureInvert(false);
0518 
0519     style->bevelAndEmboss()->setStyle(psd_bevel_outer_bevel);
0520     style->bevelAndEmboss()->setDirection(psd_direction_down);
0521     style->bevelAndEmboss()->setSoften(0);
0522     test(style, "bevel_outer_down");
0523 
0524     style->bevelAndEmboss()->setStyle(psd_bevel_emboss);
0525     style->bevelAndEmboss()->setDirection(psd_direction_up);
0526     style->bevelAndEmboss()->setSoften(0);
0527     test(style, "bevel_emboss_up");
0528 
0529     style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss);
0530     style->bevelAndEmboss()->setDirection(psd_direction_up);
0531     style->bevelAndEmboss()->setSoften(0);
0532     test(style, "bevel_pillow_up");
0533 
0534     style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss);
0535     style->bevelAndEmboss()->setDirection(psd_direction_down);
0536     style->bevelAndEmboss()->setSoften(0);
0537     test(style, "bevel_pillow_down");
0538 
0539     style->bevelAndEmboss()->setStyle(psd_bevel_pillow_emboss);
0540     style->bevelAndEmboss()->setDirection(psd_direction_up);
0541     style->bevelAndEmboss()->setSoften(3);
0542     test(style, "bevel_pillow_up_soft");
0543 }
0544 
0545 #include "kis_ls_utils.h"
0546 
0547 void KisLayerStyleProjectionPlaneTest::testBlending()
0548 {
0549     const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8();
0550     KisPaintDeviceSP layer = new KisPaintDevice(cs);
0551     KisPaintDeviceSP overlay = new KisPaintDevice(cs);
0552     KisPaintDeviceSP bg = new KisPaintDevice(cs);
0553     KisPaintDeviceSP result = new KisPaintDevice(cs);
0554 
0555     const int width = 20;
0556 
0557     QVector<QColor> layerColors;
0558     QVector<QColor> overlayColors;
0559     QVector<QColor> bgColors;
0560 
0561     layerColors << QColor(0,   255, 0);
0562     layerColors << QColor(128, 255, 64);
0563 
0564     overlayColors << QColor(255,   0, 0);
0565     overlayColors << QColor(255, 128, 64);
0566 
0567     bgColors << QColor(0, 0, 0, 0);
0568     bgColors << QColor(0, 0, 0, 255);
0569     bgColors << QColor(255, 255, 255, 255);
0570     bgColors << QColor(64, 128, 255, 255);
0571 
0572     bgColors << QColor(0, 0, 0, 128);
0573     bgColors << QColor(255, 255, 255, 128);
0574     bgColors << QColor(64, 128, 255, 128);
0575 
0576     const int overlayOpacity = 255;
0577     const int layerOpacity = 255;
0578     int y = 1;
0579     Q_FOREACH(const QColor &layerColor, layerColors) {
0580         Q_FOREACH(const QColor &overlayColor, overlayColors) {
0581             Q_FOREACH(const QColor &bgColor, bgColors) {
0582                 bg->setPixel(0, y, layerColor);
0583                 bg->setPixel(1, y, overlayColor);
0584                 bg->setPixel(2, y, bgColor);
0585                 bg->setPixel(3, y, QColor(layerOpacity, layerOpacity, layerOpacity, 255));
0586                 bg->setPixel(4, y, QColor(overlayOpacity, overlayOpacity, overlayOpacity, 255));
0587 
0588                 for (int i = 5; i < width; i++) {
0589                     bg->setPixel(i, y, bgColor);
0590                 }
0591 
0592                 for (int i = 0; i <= 10; i++) {
0593                     const quint8 alpha = i == 0 ? 71 : qRound(255 * qreal(i) / 10);
0594 
0595                     {
0596                         QColor c(layerColor);
0597                         c.setAlpha(alpha);
0598                         layer->setPixel(7 + i, y, c);
0599                     }
0600 
0601                     {
0602                         QColor c(overlayColor);
0603                         c.setAlpha(alpha);
0604                         overlay->setPixel(7 + i, y, c);
0605                     }
0606                 }
0607 
0608                 y++;
0609             }
0610         }
0611     }
0612 
0613     const QRect rc = bg->exactBounds() | layer->exactBounds();
0614 
0615 
0616     KIS_DUMP_DEVICE_2(layer, rc, "00_layer", "dd");
0617     KIS_DUMP_DEVICE_2(overlay, rc, "01_overlay", "dd");
0618     KIS_DUMP_DEVICE_2(bg, rc, "02_bg", "dd");
0619 
0620     KisPaintDeviceSP originalBg = new KisPaintDevice(*bg);
0621 
0622     KisSelectionSP selection = new KisSelection();
0623     KisLsUtils::selectionFromAlphaChannel(layer, selection, rc);
0624 
0625     {
0626         KisSequentialIterator it(layer, rc);
0627         while (it.nextPixel()) {
0628             cs->setOpacity(it.rawData(), quint8(255), 1);
0629         }
0630     }
0631 
0632     {
0633         KisSequentialIterator it(overlay, rc);
0634         while (it.nextPixel()) {
0635             cs->setOpacity(it.rawData(), quint8(255), 1);
0636         }
0637     }
0638 
0639     KisPainter painter(bg);
0640 
0641     painter.setOpacity(layerOpacity);
0642     painter.setCompositeOpId(COMPOSITE_OVER);
0643 
0644     painter.bitBlt(rc.topLeft(), layer, rc);
0645 
0646     painter.setOpacity(overlayOpacity);
0647     painter.setCompositeOpId(COMPOSITE_ADD);
0648 
0649     painter.bitBlt(rc.topLeft(), overlay, rc);
0650 
0651     KIS_DUMP_DEVICE_2(bg, rc, "03_result", "dd");
0652 
0653     KisPainter bgPainter(originalBg);
0654     bgPainter.setCompositeOpId(COMPOSITE_COPY);
0655     bgPainter.setSelection(selection);
0656     bgPainter.bitBlt(rc.topLeft(), bg, rc);
0657 
0658     KIS_DUMP_DEVICE_2(originalBg, rc, "04_knockout", "dd");
0659 }
0660 
0661 KISTEST_MAIN(KisLayerStyleProjectionPlaneTest)