1 /*
2  *  Copyright (c) 2015 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include "kis_image_animation_interface_test.h"
20 
21 #include <QTest>
22 
23 #include <testutil.h>
24 #include <KoColor.h>
25 
26 #include "kundo2command.h"
27 
28 #include "kis_debug.h"
29 
30 #include "kis_image_animation_interface.h"
31 #include "kis_signal_compressor_with_param.h"
32 #include "kis_raster_keyframe_channel.h"
33 #include "kis_time_range.h"
34 
35 
checkFrame(KisImageAnimationInterface * i,KisImageSP image,int frameId,bool externalFrameActive,const QRect & rc)36 void checkFrame(KisImageAnimationInterface *i, KisImageSP image, int frameId, bool externalFrameActive, const QRect &rc)
37 {
38     QCOMPARE(i->currentTime(), frameId);
39     QCOMPARE(i->externalFrameActive(), externalFrameActive);
40     QCOMPARE(image->projection()->exactBounds(), rc);
41 }
42 
testFrameRegeneration()43 void KisImageAnimationInterfaceTest::testFrameRegeneration()
44 {
45     QRect refRect(QRect(0,0,512,512));
46     TestUtil::MaskParent p(refRect);
47 
48     KisPaintLayerSP layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8);
49     p.image->addNode(layer2);
50 
51     const QRect rc1(101,101,100,100);
52     const QRect rc2(102,102,100,100);
53     const QRect rc3(103,103,100,100);
54     const QRect rc4(104,104,100,100);
55 
56     KisImageAnimationInterface *i = p.image->animationInterface();
57     KisPaintDeviceSP dev1 = p.layer->paintDevice();
58     KisPaintDeviceSP dev2 = layer2->paintDevice();
59 
60     p.layer->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
61     layer2->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
62 
63     // check frame 0
64     {
65         dev1->fill(rc1, KoColor(Qt::red, dev1->colorSpace()));
66         QCOMPARE(dev1->exactBounds(), rc1);
67 
68         dev2->fill(rc2, KoColor(Qt::green, dev1->colorSpace()));
69         QCOMPARE(dev2->exactBounds(), rc2);
70 
71         p.image->refreshGraph();
72         checkFrame(i, p.image, 0, false, rc1 | rc2);
73     }
74 
75     // switch/create frame 10
76     i->switchCurrentTimeAsync(10);
77     p.image->waitForDone();
78 
79     KisKeyframeChannel *channel1 = dev1->keyframeChannel();
80     channel1->addKeyframe(10);
81 
82     KisKeyframeChannel *channel2 = dev2->keyframeChannel();
83     channel2->addKeyframe(10);
84 
85 
86     // check frame 10
87     {
88         QVERIFY(dev1->exactBounds().isEmpty());
89         QVERIFY(dev2->exactBounds().isEmpty());
90 
91         dev1->fill(rc3, KoColor(Qt::red, dev2->colorSpace()));
92         QCOMPARE(dev1->exactBounds(), rc3);
93 
94         dev2->fill(rc4, KoColor(Qt::green, dev2->colorSpace()));
95         QCOMPARE(dev2->exactBounds(), rc4);
96 
97         p.image->refreshGraph();
98         checkFrame(i, p.image, 10, false, rc3 | rc4);
99     }
100 
101 
102     // check external frame (frame 0)
103     {
104         SignalToFunctionProxy proxy1(std::bind(checkFrame, i, p.image, 0, true, rc1 | rc2));
105         connect(i, SIGNAL(sigFrameReady(int)), &proxy1, SLOT(start()), Qt::DirectConnection);
106         i->requestFrameRegeneration(0, KisRegion(refRect));
107         QTest::qWait(200);
108     }
109 
110     // current frame (flame 10) is still unchanged
111     checkFrame(i, p.image, 10, false, rc3 | rc4);
112 
113     // switch back to frame 0
114     i->switchCurrentTimeAsync(0);
115     p.image->waitForDone();
116 
117     // check frame 0
118     {
119         QCOMPARE(dev1->exactBounds(), rc1);
120         QCOMPARE(dev2->exactBounds(), rc2);
121 
122         checkFrame(i, p.image, 0, false, rc1 | rc2);
123     }
124 
125     // check external frame (frame 10)
126     {
127         SignalToFunctionProxy proxy2(std::bind(checkFrame, i, p.image, 10, true, rc3 | rc4));
128         connect(i, SIGNAL(sigFrameReady(int)), &proxy2, SLOT(start()), Qt::DirectConnection);
129         i->requestFrameRegeneration(10, KisRegion(refRect));
130         QTest::qWait(200);
131     }
132 
133     // current frame is still unchanged
134     checkFrame(i, p.image, 0, false, rc1 | rc2);
135 }
136 
testFramesChangedSignal()137 void KisImageAnimationInterfaceTest::testFramesChangedSignal()
138 {
139     QRect refRect(QRect(0,0,512,512));
140     TestUtil::MaskParent p(refRect);
141 
142     KisPaintLayerSP layer1 = p.layer;
143     KisPaintLayerSP layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8);
144     p.image->addNode(layer2);
145 
146     layer1->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
147     layer2->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
148 
149     KisImageAnimationInterface *i = p.image->animationInterface();
150     KisPaintDeviceSP dev1 = p.layer->paintDevice();
151     KisPaintDeviceSP dev2 = layer2->paintDevice();
152 
153     KisKeyframeChannel *channel = dev2->keyframeChannel();
154     channel->addKeyframe(10);
155     channel->addKeyframe(20);
156 
157     // check switching a frame doesn't invalidate cache
158     QSignalSpy spy(i, SIGNAL(sigFramesChanged(KisTimeRange,QRect)));
159 
160     p.image->animationInterface()->switchCurrentTimeAsync(15);
161     p.image->waitForDone();
162 
163     QCOMPARE(spy.count(), 0);
164 
165     i->notifyNodeChanged(layer1.data(), QRect(), false);
166 
167     QCOMPARE(spy.count(), 1);
168     QList<QVariant> arguments = spy.takeFirst();
169     QCOMPARE(arguments.at(0).value<KisTimeRange>(), KisTimeRange::infinite(0));
170 
171     i->notifyNodeChanged(layer2.data(), QRect(), false);
172 
173     QCOMPARE(spy.count(), 1);
174     arguments = spy.takeFirst();
175     QCOMPARE(arguments.at(0).value<KisTimeRange>(), KisTimeRange(10, 10));
176 
177     // Recursive
178 
179     channel = dev1->keyframeChannel();
180     channel->addKeyframe(13);
181 
182     spy.clear();
183     i->notifyNodeChanged(p.image->root().data(), QRect(), true);
184 
185     QCOMPARE(spy.count(), 1);
186     arguments = spy.takeFirst();
187     QEXPECT_FAIL("", "Infinite time range is expected to be (0, -2147483648), but is (1, -2147483648)", Continue);
188     QCOMPARE(arguments.at(0).value<KisTimeRange>(), KisTimeRange::infinite(10));
189 
190 }
191 
testAnimationCompositionBug()192 void KisImageAnimationInterfaceTest::testAnimationCompositionBug()
193 {
194     QRect rect(QRect(0,0,512,512));
195     TestUtil::MaskParent p(rect);
196 
197     KUndo2Command parentCommand;
198 
199     KisPaintLayerSP layer1 = p.layer;
200     KisPaintLayerSP layer2 = new KisPaintLayer(p.image, "paint2", OPACITY_OPAQUE_U8);
201     p.image->addNode(layer2);
202 
203     layer1->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
204     layer2->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
205 
206     layer1->paintDevice()->fill(rect, KoColor(Qt::red, layer1->paintDevice()->colorSpace()));
207     layer2->paintDevice()->fill(QRect(128,128,128,128), KoColor(Qt::black, layer2->paintDevice()->colorSpace()));
208 
209     KisKeyframeChannel *rasterChannel = layer2->getKeyframeChannel(KisKeyframeChannel::Content.id());
210     rasterChannel->addKeyframe(10, &parentCommand);
211     p.image->refreshGraph();
212 
213     m_image = p.image;
214     connect(p.image->animationInterface(), SIGNAL(sigFrameReady(int)), this, SLOT(slotFrameDone()), Qt::DirectConnection);
215     p.image->animationInterface()->requestFrameRegeneration(5, rect);
216     QTest::qWait(200);
217 
218     KisPaintDeviceSP tmpDevice = new KisPaintDevice(p.image->colorSpace());
219     tmpDevice->fill(rect, KoColor(Qt::red, tmpDevice->colorSpace()));
220     tmpDevice->fill(QRect(128,128,128,128), KoColor(Qt::black, tmpDevice->colorSpace()));
221     QImage expected = tmpDevice->createThumbnail(512, 512);
222 
223     QVERIFY(m_compositedFrame == expected);
224 }
225 
slotFrameDone()226 void KisImageAnimationInterfaceTest::slotFrameDone()
227 {
228     m_compositedFrame = m_image->projection()->createThumbnail(512, 512);
229 }
230 
testSwitchFrameWithUndo()231 void KisImageAnimationInterfaceTest::testSwitchFrameWithUndo()
232 {
233         QRect refRect(QRect(0,0,512,512));
234     TestUtil::MaskParent p(refRect);
235 
236     KisPaintLayerSP layer1 = p.layer;
237 
238     layer1->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
239 
240     KisImageAnimationInterface *i = p.image->animationInterface();
241     KisPaintDeviceSP dev1 = p.layer->paintDevice();
242 
243     KisKeyframeChannel *channel = dev1->keyframeChannel();
244     channel->addKeyframe(10);
245     channel->addKeyframe(20);
246 
247 
248     QCOMPARE(i->currentTime(), 0);
249 
250     i->requestTimeSwitchWithUndo(15);
251     QTest::qWait(100);
252     p.image->waitForDone();
253     QCOMPARE(i->currentTime(), 15);
254 
255     i->requestTimeSwitchWithUndo(16);
256     QTest::qWait(100);
257     p.image->waitForDone();
258     QCOMPARE(i->currentTime(), 16);
259 
260     // the two commands have been merged!
261     p.undoStore->undo();
262     QTest::qWait(100);
263     p.image->waitForDone();
264     QCOMPARE(i->currentTime(), 0);
265 
266     p.undoStore->redo();
267     QTest::qWait(100);
268     p.image->waitForDone();
269     QCOMPARE(i->currentTime(), 16);
270 }
271 #include "kis_processing_applicator.h"
testSwitchFrameHangup()272 void KisImageAnimationInterfaceTest::testSwitchFrameHangup()
273 {
274     QRect refRect(QRect(0,0,512,512));
275     TestUtil::MaskParent p(refRect);
276 
277     KisPaintLayerSP layer1 = p.layer;
278 
279     layer1->getKeyframeChannel(KisKeyframeChannel::Content.id(), true);
280 
281     KisImageAnimationInterface *i = p.image->animationInterface();
282     KisPaintDeviceSP dev1 = p.layer->paintDevice();
283 
284     KisKeyframeChannel *channel = dev1->keyframeChannel();
285     channel->addKeyframe(10);
286     channel->addKeyframe(20);
287 
288 
289     QCOMPARE(i->currentTime(), 0);
290 
291     i->requestTimeSwitchWithUndo(15);
292     QTest::qWait(100);
293     p.image->waitForDone();
294     QCOMPARE(i->currentTime(), 15);
295 
296     KisProcessingApplicator applicator(p.image, 0);
297 
298     i->requestTimeSwitchWithUndo(16);
299 
300     applicator.end();
301 
302     QTest::qWait(100);
303     p.image->waitForDone();
304     QCOMPARE(i->currentTime(), 16);
305 
306 
307 }
308 
309 QTEST_MAIN(KisImageAnimationInterfaceTest)
310