Bump version to 6.4-15
[LibreOffice.git] / slideshow / source / engine / effectrewinder.cxx
blob944374d1d6c852d2a5789ab65fd9bfb57c4dfc8f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "effectrewinder.hxx"
22 #include <eventqueue.hxx>
23 #include <usereventqueue.hxx>
24 #include <mouseeventhandler.hxx>
25 #include <basecontainernode.hxx>
26 #include <delayevent.hxx>
28 #include <com/sun/star/awt/MouseEvent.hpp>
29 #include <com/sun/star/animations/Event.hpp>
30 #include <com/sun/star/animations/EventTrigger.hpp>
31 #include <com/sun/star/container/XEnumerationAccess.hpp>
32 #include <com/sun/star/animations/XAnimate.hpp>
34 #include <officecfg/Office/Canvas.hxx>
36 using ::com::sun::star::uno::Reference;
37 using namespace ::com::sun::star;
39 namespace slideshow { namespace internal {
42 namespace {
44 class RewinderEventHandler : public EventHandler
46 public:
47 typedef ::std::function<bool ()> Action;
48 explicit RewinderEventHandler (const Action& rAction) : maAction(rAction) {}
50 private:
51 const Action maAction;
52 virtual bool handleEvent() override { return maAction(); }
56 class RewinderAnimationEventHandler : public AnimationEventHandler
58 public:
59 typedef ::std::function<bool (const AnimationNodeSharedPtr& rpNode)> Action;
60 explicit RewinderAnimationEventHandler (const Action& rAction) : maAction(rAction) {}
62 private:
63 const Action maAction;
64 virtual bool handleAnimationEvent (const AnimationNodeSharedPtr& rpNode) override
65 { return maAction(rpNode); }
69 } // end of anonymous namespace
72 //----- EffectRewinder --------------------------------------------------------------
74 EffectRewinder::EffectRewinder (
75 EventMultiplexer& rEventMultiplexer,
76 EventQueue& rEventQueue,
77 UserEventQueue& rUserEventQueue)
78 : mrEventMultiplexer(rEventMultiplexer),
79 mrEventQueue(rEventQueue),
80 mrUserEventQueue(rUserEventQueue),
81 mpSlideStartHandler(),
82 mpSlideEndHandler(),
83 mpAnimationStartHandler(),
84 mnMainSequenceEffectCount(0),
85 mpAsynchronousRewindEvent(),
86 mxCurrentAnimationRootNode(),
87 mbNonUserTriggeredMainSequenceEffectSeen(false)
89 initialize();
93 void EffectRewinder::initialize()
95 // Add some event handlers so that we are informed when
96 // a) an animation is started (we then check whether that belongs to a
97 // main sequence effect and if so, increase the respective counter),
98 // b,c) a slide was started or ended (in which case the effect counter
99 // is reset.
101 mpAnimationStartHandler.reset(
102 new RewinderAnimationEventHandler(
103 [this]( const AnimationNodeSharedPtr& pNode)
104 { return this->notifyAnimationStart( pNode ); } ) );
105 mrEventMultiplexer.addAnimationStartHandler(mpAnimationStartHandler);
107 mpSlideStartHandler.reset(
108 new RewinderEventHandler(
109 [this]() { return this->resetEffectCount(); } ) );
110 mrEventMultiplexer.addSlideStartHandler(mpSlideStartHandler);
112 mpSlideEndHandler.reset(
113 new RewinderEventHandler(
114 [this]() { return this->resetEffectCount(); } ) );
115 mrEventMultiplexer.addSlideEndHandler(mpSlideEndHandler);
119 EffectRewinder::~EffectRewinder()
121 dispose();
125 void EffectRewinder::dispose()
127 if (mpAsynchronousRewindEvent)
129 mpAsynchronousRewindEvent->dispose();
130 mpAsynchronousRewindEvent.reset();
133 if (mpAnimationStartHandler)
135 mrEventMultiplexer.removeAnimationStartHandler(mpAnimationStartHandler);
136 mpAnimationStartHandler.reset();
139 if (mpSlideStartHandler)
141 mrEventMultiplexer.removeSlideStartHandler(mpSlideStartHandler);
142 mpSlideStartHandler.reset();
145 if (mpSlideEndHandler)
147 mrEventMultiplexer.removeSlideEndHandler(mpSlideEndHandler);
148 mpSlideEndHandler.reset();
153 void EffectRewinder::setRootAnimationNode (
154 const uno::Reference<animations::XAnimationNode>& xRootNode)
156 mxCurrentAnimationRootNode = xRootNode;
160 bool EffectRewinder::rewind (
161 const ::std::shared_ptr<ScreenUpdater::UpdateLock>& rpPaintLock,
162 const ::std::function<void ()>& rSlideRewindFunctor,
163 const ::std::function<void ()>& rPreviousSlideFunctor)
165 mpPaintLock = rpPaintLock;
167 // Do not allow nested rewinds.
168 if (mpAsynchronousRewindEvent)
170 OSL_ASSERT( ! mpAsynchronousRewindEvent);
171 return false;
174 // Abort (and skip over the rest of) any currently active animation.
175 mrUserEventQueue.callSkipEffectEventHandler();
177 const int nSkipCount (mnMainSequenceEffectCount - 1);
178 if (nSkipCount < 0)
180 if ( ! rPreviousSlideFunctor)
182 OSL_ASSERT(rPreviousSlideFunctor);
183 return false;
186 // No main sequence effects to rewind on the current slide.
187 // Go back to the previous slide.
188 mpAsynchronousRewindEvent = makeEvent(
189 ::std::bind(
190 &EffectRewinder::asynchronousRewindToPreviousSlide,
191 this,
192 rPreviousSlideFunctor),
193 "EffectRewinder::asynchronousRewindToPreviousSlide");
195 else
197 // The actual rewinding is done asynchronously so that we can safely
198 // call other methods.
199 mpAsynchronousRewindEvent = makeEvent(
200 ::std::bind(
201 &EffectRewinder::asynchronousRewind,
202 this,
203 nSkipCount,
204 true,
205 rSlideRewindFunctor),
206 "EffectRewinder::asynchronousRewind");
209 if (mpAsynchronousRewindEvent)
210 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
212 return mpAsynchronousRewindEvent.get()!=nullptr;
216 void EffectRewinder::skipAllMainSequenceEffects()
218 // Do not allow nested rewinds.
219 if (mpAsynchronousRewindEvent)
221 OSL_ASSERT(!mpAsynchronousRewindEvent);
222 return;
225 const int nTotalMainSequenceEffectCount (countMainSequenceEffects());
226 mpAsynchronousRewindEvent = makeEvent(
227 ::std::bind(
228 &EffectRewinder::asynchronousRewind,
229 this,
230 nTotalMainSequenceEffectCount,
231 false,
232 ::std::function<void ()>()),
233 "EffectRewinder::asynchronousRewind");
234 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
238 sal_Int32 EffectRewinder::countMainSequenceEffects()
240 // Determine the number of main sequence effects.
241 sal_Int32 nMainSequenceNodeCount (0);
243 ::std::queue<uno::Reference<animations::XAnimationNode> > aNodeQueue;
244 aNodeQueue.push(mxCurrentAnimationRootNode);
245 while ( ! aNodeQueue.empty())
247 const uno::Reference<animations::XAnimationNode> xNode (aNodeQueue.front());
248 aNodeQueue.pop();
250 // Does the current node belong to the main sequence?
251 if (xNode.is())
253 animations::Event aEvent;
254 if (xNode->getBegin() >>= aEvent)
255 if (aEvent.Trigger == animations::EventTrigger::ON_NEXT)
256 ++nMainSequenceNodeCount;
259 // If the current node is a container then prepare its children for investigation.
260 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
261 if (xEnumerationAccess.is())
263 uno::Reference<container::XEnumeration> xEnumeration (
264 xEnumerationAccess->createEnumeration());
265 if (xEnumeration.is())
266 while (xEnumeration->hasMoreElements())
268 aNodeQueue.push(
269 uno::Reference<animations::XAnimationNode>(
270 xEnumeration->nextElement(), uno::UNO_QUERY));
275 return nMainSequenceNodeCount;
279 void EffectRewinder::skipSingleMainSequenceEffects()
281 // This basically just starts the next effect and then skips over its
282 // animation.
283 mrEventMultiplexer.notifyNextEffect();
284 mrEventQueue.forceEmpty();
285 mrUserEventQueue.callSkipEffectEventHandler();
286 mrEventQueue.forceEmpty();
290 bool EffectRewinder::resetEffectCount()
292 mnMainSequenceEffectCount = 0;
293 return false;
296 bool EffectRewinder::hasBlockedAnimation( const css::uno::Reference<css::animations::XAnimationNode>& xNode)
298 bool isShapeTarget = false;;
299 OUString preset_id;
300 OUString preset_sub_type;
301 OUString preset_property;
303 if (xNode->getUserData().getLength())
305 for(int i = 0; i < xNode->getUserData().getLength(); i++)
307 if(xNode->getUserData()[i].Name == "preset-id")
308 xNode->getUserData()[i].Value >>= preset_id;
309 if(xNode->getUserData()[i].Name == "preset-sub-type")
310 xNode->getUserData()[i].Value >>= preset_sub_type;
311 if(xNode->getUserData()[i].Name == "preset-property")
312 xNode->getUserData()[i].Value >>= preset_property;
316 uno::Reference<container::XEnumerationAccess> xEnumerationAccess (xNode, uno::UNO_QUERY);
317 if (xEnumerationAccess.is())
319 uno::Reference<container::XEnumeration> xEnumeration (
320 xEnumerationAccess->createEnumeration());
321 if (xEnumeration.is())
322 while (xEnumeration->hasMoreElements())
324 uno::Reference<animations::XAnimationNode> xNext (xEnumeration->nextElement(), uno::UNO_QUERY);
325 uno::Reference<animations::XAnimate> xAnimate( xNext, uno::UNO_QUERY );
327 if(xAnimate.is())
329 uno::Reference< drawing::XShape > xShape( xAnimate->getTarget(), uno::UNO_QUERY );
331 if (xShape.is() || xAnimate->getTarget().getValueType() == cppu::UnoType<void>::get())
332 isShapeTarget=true;
337 if(isShapeTarget &&
338 ((preset_id == "ooo-entrance-zoom" && preset_sub_type == "in") || // Entrance Zoom In
339 (preset_id == "ooo-entrance-swivel" ) || // Entrance Swivel
340 (preset_id == "ooo-entrance-spiral-in") || // Entrance Spiral-In
341 (preset_id == "ooo-entrance-stretchy"))) // Entrance Stretchy
342 return true;
344 return false;
347 bool EffectRewinder::notifyAnimationStart (const AnimationNodeSharedPtr& rpNode)
349 Reference<animations::XAnimationNode> xNode (rpNode->getXAnimationNode());
351 if( xNode.is() &&
352 !officecfg::Office::Canvas::ForceSafeServiceImpl::get() &&
353 hasBlockedAnimation(xNode) )
354 skipSingleMainSequenceEffects();
356 // This notification is only relevant for us when the rpNode belongs to
357 // the main sequence.
358 BaseNodeSharedPtr pBaseNode (::std::dynamic_pointer_cast<BaseNode>(rpNode));
359 if ( ! pBaseNode)
360 return false;
362 BaseContainerNodeSharedPtr pParent (pBaseNode->getParentNode());
363 if ( ! (pParent && pParent->isMainSequenceRootNode()))
364 return false;
366 // This notification is only relevant for us when the effect is user
367 // triggered.
368 bool bIsUserTriggered (false);
370 if (xNode.is())
372 animations::Event aEvent;
373 if (xNode->getBegin() >>= aEvent)
374 bIsUserTriggered = (aEvent.Trigger == animations::EventTrigger::ON_NEXT);
377 if (bIsUserTriggered)
378 ++mnMainSequenceEffectCount;
379 else
380 mbNonUserTriggeredMainSequenceEffectSeen = true;
382 return false;
386 void EffectRewinder::asynchronousRewind (
387 sal_Int32 nEffectCount,
388 const bool bRedisplayCurrentSlide,
389 const std::function<void ()>& rSlideRewindFunctor)
391 OSL_ASSERT(mpAsynchronousRewindEvent);
393 if (bRedisplayCurrentSlide)
395 mpPaintLock->Activate();
396 // Re-display the current slide.
397 if (rSlideRewindFunctor)
398 rSlideRewindFunctor();
399 mpAsynchronousRewindEvent = makeEvent(
400 ::std::bind(
401 &EffectRewinder::asynchronousRewind,
402 this,
403 nEffectCount,
404 false,
405 rSlideRewindFunctor),
406 "EffectRewinder::asynchronousRewind");
407 mrEventQueue.addEvent(mpAsynchronousRewindEvent);
409 else
411 // Process initial events and skip any animations that are started
412 // when the slide is shown.
413 mbNonUserTriggeredMainSequenceEffectSeen = false;
415 if (mbNonUserTriggeredMainSequenceEffectSeen)
417 mrUserEventQueue.callSkipEffectEventHandler();
418 mrEventQueue.forceEmpty();
421 while (--nEffectCount >= 0)
422 skipSingleMainSequenceEffects();
424 mpAsynchronousRewindEvent.reset();
425 mpPaintLock.reset();
430 void EffectRewinder::asynchronousRewindToPreviousSlide (
431 const ::std::function<void ()>& rSlideRewindFunctor)
433 OSL_ASSERT(mpAsynchronousRewindEvent);
435 mpAsynchronousRewindEvent.reset();
436 rSlideRewindFunctor();
440 } } // end of namespace ::slideshow::internal
442 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */