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