1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 #include <canvas/debug.hxx>
28 #include <tools/diagnose_ex.h>
29 
30 #include <cppuhelper/basemutex.hxx>
31 #include <cppuhelper/compbase1.hxx>
32 #include <cppuhelper/factory.hxx>
33 #include <cppuhelper/implementationentry.hxx>
34 #include <cppuhelper/compbase2.hxx>
35 #include <cppuhelper/interfacecontainer.h>
36 #include <cppuhelper/exc_hlp.hxx>
37 
38 #include <comphelper/anytostring.hxx>
39 #include <comphelper/make_shared_from_uno.hxx>
40 #include <comphelper/scopeguard.hxx>
41 #include <comphelper/optional.hxx>
42 #include <comphelper/servicedecl.hxx>
43 #include <comphelper/namecontainer.hxx>
44 
45 #include <cppcanvas/spritecanvas.hxx>
46 #include <cppcanvas/vclfactory.hxx>
47 #include <cppcanvas/basegfxfactory.hxx>
48 
49 #include <tools/debug.hxx>
50 
51 #include <basegfx/point/b2dpoint.hxx>
52 #include <basegfx/polygon/b2dpolygon.hxx>
53 #include <basegfx/matrix/b2dhommatrix.hxx>
54 #include <basegfx/polygon/b2dpolygontools.hxx>
55 #include <basegfx/polygon/b2dpolypolygontools.hxx>
56 #include <basegfx/tools/canvastools.hxx>
57 
58 #include <vcl/font.hxx>
59 #include "rtl/ref.hxx"
60 
61 #include <com/sun/star/beans/XPropertySet.hpp>
62 #include <com/sun/star/util/XModifyListener.hpp>
63 #include <com/sun/star/util/XUpdatable.hpp>
64 #include <com/sun/star/awt/XPaintListener.hpp>
65 #include <com/sun/star/awt/SystemPointer.hpp>
66 #include <com/sun/star/animations/TransitionType.hpp>
67 #include <com/sun/star/animations/TransitionSubType.hpp>
68 #include <com/sun/star/presentation/XSlideShow.hpp>
69 #include <com/sun/star/presentation/XSlideShowListener.hpp>
70 #include <com/sun/star/lang/XServiceInfo.hpp>
71 #include <com/sun/star/lang/XServiceName.hpp>
72 #include <com/sun/star/lang/XComponent.hpp>
73 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
74 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
75 #include <com/sun/star/drawing/PointSequence.hpp>
76 #include <com/sun/star/drawing/XLayer.hpp>
77 #include <com/sun/star/drawing/XLayerSupplier.hpp>
78 #include <com/sun/star/drawing/XLayerManager.hpp>
79 #include <com/sun/star/container/XNameAccess.hpp>
80 
81 #include "com/sun/star/uno/Reference.hxx"
82 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
83 
84 #include "unoviewcontainer.hxx"
85 #include "transitionfactory.hxx"
86 #include "eventmultiplexer.hxx"
87 #include "usereventqueue.hxx"
88 #include "eventqueue.hxx"
89 #include "cursormanager.hxx"
90 #include "slideshowcontext.hxx"
91 #include "activitiesqueue.hxx"
92 #include "activitiesfactory.hxx"
93 #include "interruptabledelayevent.hxx"
94 #include "slide.hxx"
95 #include "shapemaps.hxx"
96 #include "slideview.hxx"
97 #include "tools.hxx"
98 #include "unoview.hxx"
99 #include "slidebitmap.hxx"
100 #include "rehearsetimingsactivity.hxx"
101 #include "waitsymbol.hxx"
102 #include "effectrewinder.hxx"
103 #include "framerate.hxx"
104 
105 #include <boost/noncopyable.hpp>
106 #include <boost/bind.hpp>
107 
108 #include <map>
109 #include <vector>
110 #include <iterator>
111 #include <string>
112 #include <algorithm>
113 #include <stdio.h>
114 #include <iostream>
115 
116 using namespace com::sun::star;
117 using namespace ::slideshow::internal;
118 
119 namespace {
120 
121 /** During animations the update() method tells its caller to call it as
122     soon as possible. This gives us more time to render the next frame and
123     still maintain a steady frame rate. This class is responsible for
124     synchronizing the display of new frames and thus keeping the frame rate
125     steady.
126 */
127 class FrameSynchronization
128 {
129 public:
130     /** Create new object with a predefined duration between two frames.
131         @param nFrameDuration
132             The preferred duration between the display of two frames in
133             seconds.
134     */
135     FrameSynchronization (const double nFrameDuration);
136 
137     /** Set the current time as the time at which the current frame is
138         displayed. From this the target time of the next frame is derived.
139     */
140     void MarkCurrentFrame (void);
141 
142     /** When there is time left until the next frame is due then wait.
143         Otherwise return without delay.
144     */
145     void Synchronize (void);
146 
147     /** Activate frame synchronization when an animation is active and
148         frames are to be displayed in a steady rate. While active
149         Synchronize() will wait until the frame duration time has passed.
150     */
151     void Activate (void);
152 
153     /** Deactivate frame synchronization when no animation is active and the
154         time between frames depends on user actions and other external
155         sources. While deactivated Synchronize() will return without delay.
156     */
157     void Deactivate (void);
158 
159     /** Return the current time of the timer. It is not synchronized with
160         any other timer so its absolute values are of no concern. Typically
161         used during debugging to measure durations.
162     */
163     double GetCurrentTime (void) const;
164 
165 private:
166     /** The timer that is used for synchronization is independent from the
167         one used by SlideShowImpl: it is not paused or modified by
168         animations.
169     */
170     canvas::tools::ElapsedTime maTimer;
171     /** Time between the display of frames. Enforced only when mbIsActive
172         is <TRUE/>.
173     */
174     const double mnFrameDuration;
175     /** Time (of maTimer) when the next frame shall be displayed.
176         Synchronize() will wait until this time.
177     */
178     double mnNextFrameTargetTime;
179     /** Synchronize() will wait only when this flag is <TRUE/>. Otherwise
180         it returns immediately.
181     */
182     bool mbIsActive;
183 };
184 
185 
186 
187 
188 /******************************************************************************
189 
190    SlideShowImpl
191 
192    This class encapsulates the slideshow presentation viewer.
193 
194    With an instance of this class, it is possible to statically
195    and dynamically show a presentation, as defined by the
196    constructor-provided draw model (represented by a sequence
197    of ::com::sun::star::drawing::XDrawPage objects).
198 
199    It is possible to show the presentation on multiple views
200    simultaneously (e.g. for a multi-monitor setup). Since this
201    class also relies on user interaction, the corresponding
202    XSlideShowView interface provides means to register some UI
203    event listeners (mostly borrowed from awt::XWindow interface).
204 
205    Since currently (mid 2004), AOO isn't very well suited to
206    multi-threaded rendering, this class relies on <em>very
207    frequent</em> external update() calls, which will render the
208    next frame of animations. This works as follows: after the
209    displaySlide() has been successfully called (which setup and
210    starts an actual slide show), the update() method must be
211    called until it returns false.
212    Effectively, this puts the burden of providing
213    concurrency to the clients of this class, which, as noted
214    above, is currently unavoidable with the current state of
215    affairs (I've actually tried threading here, but failed
216    miserably when using the VCL canvas as the render backend -
217    deadlocked).
218 
219  ******************************************************************************/
220 
221 typedef cppu::WeakComponentImplHelper1<presentation::XSlideShow> SlideShowImplBase;
222 
223 typedef ::std::vector< ::cppcanvas::PolyPolygonSharedPtr> PolyPolygonVector;
224 
225 // Maps XDrawPage for annotations persistence
226 typedef ::std::map< ::com::sun::star::uno::Reference<
227                                     ::com::sun::star::drawing::XDrawPage>,
228                                     PolyPolygonVector>  PolygonMap;
229 
230 class SlideShowImpl : private cppu::BaseMutex,
231                       public CursorManager,
232                       public SlideShowImplBase
233 {
234 public:
235     explicit SlideShowImpl(
236         uno::Reference<uno::XComponentContext> const& xContext );
237 
238     /** Notify that the transition phase of the current slide
239         has ended.
240 
241         The life of a slide has three phases: the transition
242         phase, when the previous slide vanishes, and the
243         current slide becomes visible, the shape animation
244         phase, when shape effects are running, and the phase
245         after the last shape animation has ended, but before
246         the next slide transition starts.
247 
248         This method notifies the end of the first phase.
249 
250         @param bPaintSlide
251         When true, Slide::show() is passed a true as well, denoting
252         explicit paint of slide content. Pass false here, if e.g. a
253         slide transition has already rendered the initial slide image.
254     */
255     void notifySlideTransitionEnded( bool bPaintSlide );
256 
257     /** Notify that the shape animation phase of the current slide
258         has ended.
259 
260         The life of a slide has three phases: the transition
261         phase, when the previous slide vanishes, and the
262         current slide becomes visible, the shape animation
263         phase, when shape effects are running, and the phase
264         after the last shape animation has ended, but before
265         the next slide transition starts.
266 
267         This method notifies the end of the second phase.
268     */
269     void notifySlideAnimationsEnded();
270 
271     /** Notify that the slide has ended.
272 
273         The life of a slide has three phases: the transition
274         phase, when the previous slide vanishes, and the
275         current slide becomes visible, the shape animation
276         phase, when shape effects are running, and the phase
277         after the last shape animation has ended, but before
278         the next slide transition starts.
279 
280         This method notifies the end of the third phase.
281     */
282     void notifySlideEnded (const bool bReverse);
283 
284     /** Notification from eventmultiplexer that a hyperlink
285         has been clicked.
286     */
287     bool notifyHyperLinkClicked( rtl::OUString const& hyperLink );
288 
289     /** Notification from eventmultiplexer that an animation event has occurred.
290 		This will be forwarded to all registered XSlideShowListener
291      */
292 	bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode );
293 
294 private:
295     // XSlideShow:
296     virtual sal_Bool SAL_CALL nextEffect() throw (uno::RuntimeException);
297     virtual sal_Bool SAL_CALL previousEffect() throw (uno::RuntimeException);
298     virtual sal_Bool SAL_CALL startShapeActivity(
299         uno::Reference<drawing::XShape> const& xShape )
300         throw (uno::RuntimeException);
301     virtual sal_Bool SAL_CALL stopShapeActivity(
302         uno::Reference<drawing::XShape> const& xShape )
303         throw (uno::RuntimeException);
304     virtual sal_Bool SAL_CALL pause( sal_Bool bPauseShow )
305         throw (uno::RuntimeException);
306     virtual uno::Reference<drawing::XDrawPage> SAL_CALL getCurrentSlide()
307         throw (uno::RuntimeException);
308     virtual void SAL_CALL displaySlide(
309         uno::Reference<drawing::XDrawPage> const& xSlide,
310         uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
311         uno::Reference<animations::XAnimationNode> const& xRootNode,
312         uno::Sequence<beans::PropertyValue> const& rProperties )
313         throw (uno::RuntimeException);
314     virtual void SAL_CALL registerUserPaintPolygons( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& xDocFactory ) throw (::com::sun::star::uno::RuntimeException);
315     virtual sal_Bool SAL_CALL setProperty(
316         beans::PropertyValue const& rProperty ) throw (uno::RuntimeException);
317     virtual sal_Bool SAL_CALL addView(
318         uno::Reference<presentation::XSlideShowView> const& xView )
319         throw (uno::RuntimeException);
320     virtual sal_Bool SAL_CALL removeView(
321         uno::Reference<presentation::XSlideShowView> const& xView )
322         throw (uno::RuntimeException);
323     virtual sal_Bool SAL_CALL update( double & nNextTimeout )
324         throw (uno::RuntimeException);
325     virtual void SAL_CALL addSlideShowListener(
326         uno::Reference<presentation::XSlideShowListener> const& xListener )
327         throw (uno::RuntimeException);
328     virtual void SAL_CALL removeSlideShowListener(
329         uno::Reference<presentation::XSlideShowListener> const& xListener )
330         throw (uno::RuntimeException);
331     virtual void SAL_CALL addShapeEventListener(
332         uno::Reference<presentation::XShapeEventListener> const& xListener,
333         uno::Reference<drawing::XShape> const& xShape )
334         throw (uno::RuntimeException);
335     virtual void SAL_CALL removeShapeEventListener(
336         uno::Reference<presentation::XShapeEventListener> const& xListener,
337         uno::Reference<drawing::XShape> const& xShape )
338         throw (uno::RuntimeException);
339     virtual void SAL_CALL setShapeCursor(
340         uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
341         throw (uno::RuntimeException);
342 
343 
344     // CursorManager
345     // -----------------------------------------------------------
346 
347     virtual bool requestCursor( sal_Int16 nCursorShape );
348     virtual void resetCursor();
349 
350     /** This is somewhat similar to displaySlide when called for the current
351         slide. It has been simplified to take advantage of that no slide
352         change takes place. Furthermore it does not show the slide
353         transition.
354     */
355     void redisplayCurrentSlide (void);
356 
357 protected:
358     // WeakComponentImplHelperBase
359     virtual void SAL_CALL disposing();
360 
isDisposed() const361     bool isDisposed() const
362     {
363         return (rBHelper.bDisposed || rBHelper.bInDispose);
364     }
365 
366 private:
367     struct SeparateListenerImpl; friend struct SeparateListenerImpl;
368     class PrefetchPropertiesFunc; friend class PrefetchPropertiesFunc;
369 
370     // Stop currently running show.
371     void stopShow();
372 
373     // Find a polygons vector in maPolygons (map)
374     PolygonMap::iterator findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage);
375 
376     // Creates a new slide.
377     SlideSharedPtr makeSlide(
378         uno::Reference<drawing::XDrawPage> const& xDrawPage,
379         uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
380         uno::Reference<animations::XAnimationNode> const& xRootNode );
381 
382     // Checks whether the given slide/animation node matches mpPrefetchSlide
matches(SlideSharedPtr const & pSlide,uno::Reference<drawing::XDrawPage> const & xSlide,uno::Reference<animations::XAnimationNode> const & xNode)383     static bool matches(
384         SlideSharedPtr const& pSlide,
385         uno::Reference<drawing::XDrawPage> const& xSlide,
386         uno::Reference<animations::XAnimationNode> const& xNode )
387     {
388         if (pSlide)
389             return (pSlide->getXDrawPage() == xSlide &&
390                     pSlide->getXAnimationNode() == xNode);
391         else
392             return (!xSlide.is() && !xNode.is());
393     }
394 
395     // Resets the current slide transition sound object with a new one:
396     SoundPlayerSharedPtr resetSlideTransitionSound(
397 		uno::Any const& url = uno::Any(), bool bLoopSound = false );
398 
399 	// stops the current slide transition sound
400 	void stopSlideTransitionSound();
401 
402     /** Prepare a slide transition
403 
404         This method registers all necessary events and
405         activities for a slide transition.
406 
407         @return the slide change activity, or NULL for no transition effect
408     */
409     ActivitySharedPtr createSlideTransition(
410         const uno::Reference< drawing::XDrawPage >&    xDrawPage,
411         const SlideSharedPtr&                          rLeavingSlide,
412         const SlideSharedPtr&                          rEnteringSlide,
413         const EventSharedPtr&                          rTransitionEndEvent );
414 
415     /** Request/release the wait symbol. The wait symbol is displayed when
416         there are more requests then releases. Locking the wait symbol
417         helps to avoid intermediate repaints.
418 
419         Do not call this method directly. Use WaitSymbolLock instead.
420     */
421     void requestWaitSymbol (void);
422     void releaseWaitSymbol (void);
423 
424     class WaitSymbolLock {public:
WaitSymbolLock(SlideShowImpl & rSlideShowImpl)425         WaitSymbolLock(SlideShowImpl& rSlideShowImpl) : mrSlideShowImpl(rSlideShowImpl)
426             { mrSlideShowImpl.requestWaitSymbol(); }
~WaitSymbolLock(void)427         ~WaitSymbolLock(void)
428             { mrSlideShowImpl.releaseWaitSymbol(); }
429     private: SlideShowImpl& mrSlideShowImpl;
430     };
431 
432 
433     // Filter requested cursor shape against hard slideshow cursors (wait, etc.)
434     sal_Int16 calcActiveCursor( sal_Int16 nCursorShape ) const;
435 
436     /** This method is called asynchronously to finish the rewinding of an
437         effect to the previous slide that was initiated earlier.
438     */
439     void rewindEffectToPreviousSlide (void);
440 
441     // all registered views
442     UnoViewContainer                        maViewContainer;
443 
444     // all registered slide show listeners
445     cppu::OInterfaceContainerHelper         maListenerContainer;
446 
447     // map of vectors, containing all registered listeners for a shape
448     ShapeEventListenerMap                   maShapeEventListeners;
449     // map of sal_Int16 values, specifying the mouse cursor for every shape
450     ShapeCursorMap                          maShapeCursors;
451 
452     // map of vector of Polygons, containing polygons drawn on each slide.
453     PolygonMap                              maPolygons;
454 
455     boost::optional<RGBColor>               maUserPaintColor;
456 
457 	double									maUserPaintStrokeWidth;
458 
459     // changed for the eraser project
460     boost::optional<bool>		    maEraseAllInk;
461     boost::optional<bool>		    maSwitchPenMode;
462     boost::optional<bool>		    maSwitchEraserMode;
463     boost::optional<sal_Int32>		    maEraseInk;
464     // end changed
465 
466     boost::shared_ptr<canvas::tools::ElapsedTime> mpPresTimer;
467     ScreenUpdater                           maScreenUpdater;
468     EventQueue                              maEventQueue;
469     EventMultiplexer                        maEventMultiplexer;
470     ActivitiesQueue                         maActivitiesQueue;
471     UserEventQueue                          maUserEventQueue;
472     SubsettableShapeManagerSharedPtr        mpDummyPtr;
473 
474     boost::shared_ptr<SeparateListenerImpl> mpListener;
475 
476     boost::shared_ptr<RehearseTimingsActivity> mpRehearseTimingsActivity;
477     boost::shared_ptr<WaitSymbol>           mpWaitSymbol;
478 
479     // the current slide transition sound object:
480     SoundPlayerSharedPtr                    mpCurrentSlideTransitionSound;
481 
482     uno::Reference<uno::XComponentContext>  mxComponentContext;
483     uno::Reference<
484         presentation::XTransitionFactory>   mxOptionalTransitionFactory;
485 
486     // the previously running slide
487     SlideSharedPtr                          mpPreviousSlide;
488     // the currently running slide
489     SlideSharedPtr                          mpCurrentSlide;
490     // the already prefetched slide: best candidate for upcoming slide
491     SlideSharedPtr                          mpPrefetchSlide;
492     // slide to be prefetched: best candidate for upcoming slide
493     uno::Reference<drawing::XDrawPage>      mxPrefetchSlide;
494     // save the XDrawPagesSupplier to retrieve polygons
495     uno::Reference<drawing::XDrawPagesSupplier>  mxDrawPagesSupplier;
496     // slide animation to be prefetched:
497     uno::Reference<animations::XAnimationNode> mxPrefetchAnimationNode;
498 
499     sal_Int16                               mnCurrentCursor;
500 
501     sal_Int32                               mnWaitSymbolRequestCount;
502     bool                                    mbAutomaticAdvancementMode;
503     bool                                    mbImageAnimationsAllowed;
504     bool                                    mbNoSlideTransitions;
505     bool                                    mbMouseVisible;
506     bool                                    mbForceManualAdvance;
507     bool                                    mbShowPaused;
508     bool                                    mbSlideShowIdle;
509     bool                                    mbDisableAnimationZOrder;
510 
511     EffectRewinder                          maEffectRewinder;
512     FrameSynchronization                    maFrameSynchronization;
513 };
514 
515 
516 /** Separate event listener for animation, view and hyperlink events.
517 
518     This handler is registered for slide animation end, view and
519     hyperlink events at the global EventMultiplexer, and forwards
520     notifications to the SlideShowImpl
521 */
522 struct SlideShowImpl::SeparateListenerImpl : public EventHandler,
523                                              public ViewRepaintHandler,
524                                              public HyperlinkHandler,
525 											 public AnimationEventHandler,
526                                              private boost::noncopyable
527 {
528     SlideShowImpl& mrShow;
529     ScreenUpdater& mrScreenUpdater;
530     EventQueue&    mrEventQueue;
531 
SeparateListenerImpl__anon83e1a3020111::SlideShowImpl::SeparateListenerImpl532     SeparateListenerImpl( SlideShowImpl& rShow,
533                           ScreenUpdater& rScreenUpdater,
534                           EventQueue&    rEventQueue ) :
535         mrShow( rShow ),
536         mrScreenUpdater( rScreenUpdater ),
537         mrEventQueue( rEventQueue )
538     {}
539 
540     // EventHandler
handleEvent__anon83e1a3020111::SlideShowImpl::SeparateListenerImpl541     virtual bool handleEvent()
542     {
543         // DON'T call notifySlideAnimationsEnded()
544         // directly, but queue an event. handleEvent()
545         // might be called from e.g.
546         // showNext(), and notifySlideAnimationsEnded() must not be called
547         // in recursion. Note that the event is scheduled for the next
548         // frame so that its expensive execution does not come in between
549         // sprite hiding and shape redraw (at the end of the animation of a
550         // shape), which would cause a flicker.
551         mrEventQueue.addEventForNextRound(
552             makeEvent(
553                 boost::bind( &SlideShowImpl::notifySlideAnimationsEnded, boost::ref(mrShow) ),
554                 "SlideShowImpl::notifySlideAnimationsEnded"));
555         return true;
556     }
557 
558     // ViewRepaintHandler
viewClobbered__anon83e1a3020111::SlideShowImpl::SeparateListenerImpl559     virtual void viewClobbered( const UnoViewSharedPtr& rView )
560     {
561         // given view needs repaint, request update
562         mrScreenUpdater.notifyUpdate(rView, true);
563     }
564 
565     // HyperlinkHandler
handleHyperlink__anon83e1a3020111::SlideShowImpl::SeparateListenerImpl566     virtual bool handleHyperlink( ::rtl::OUString const& rLink )
567     {
568         return mrShow.notifyHyperLinkClicked(rLink);
569     }
570 
571 	// AnimationEventHandler
handleAnimationEvent__anon83e1a3020111::SlideShowImpl::SeparateListenerImpl572     virtual bool handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
573 	{
574 		return mrShow.handleAnimationEvent(rNode);
575 	}
576 };
577 
578 
SlideShowImpl(uno::Reference<uno::XComponentContext> const & xContext)579 SlideShowImpl::SlideShowImpl(
580     uno::Reference<uno::XComponentContext> const& xContext )
581     : SlideShowImplBase(m_aMutex),
582       maViewContainer(),
583       maListenerContainer( m_aMutex ),
584       maShapeEventListeners(),
585       maShapeCursors(),
586       maUserPaintColor(),
587       maUserPaintStrokeWidth(4.0),
588       mpPresTimer( new canvas::tools::ElapsedTime ),
589       maScreenUpdater(maViewContainer),
590       maEventQueue( mpPresTimer ),
591       maEventMultiplexer( maEventQueue,
592                           maViewContainer ),
593       maActivitiesQueue( mpPresTimer ),
594       maUserEventQueue( maEventMultiplexer,
595                         maEventQueue,
596                         *this ),
597       mpDummyPtr(),
598       mpListener(),
599       mpRehearseTimingsActivity(),
600       mpWaitSymbol(),
601       mpCurrentSlideTransitionSound(),
602       mxComponentContext( xContext ),
603       mxOptionalTransitionFactory(),
604       mpCurrentSlide(),
605       mpPrefetchSlide(),
606       mxPrefetchSlide(),
607       mxDrawPagesSupplier(),
608       mxPrefetchAnimationNode(),
609       mnCurrentCursor(awt::SystemPointer::ARROW),
610       mnWaitSymbolRequestCount(0),
611       mbAutomaticAdvancementMode(false),
612       mbImageAnimationsAllowed( true ),
613       mbNoSlideTransitions( false ),
614       mbMouseVisible( true ),
615       mbForceManualAdvance( false ),
616       mbShowPaused( false ),
617       mbSlideShowIdle( true ),
618       mbDisableAnimationZOrder( false ),
619       maEffectRewinder(maEventMultiplexer, maEventQueue, maUserEventQueue),
620       maFrameSynchronization(1.0 / FrameRate::PreferredFramesPerSecond)
621 
622 {
623     // keep care not constructing any UNO references to this inside ctor,
624     // shift that code to create()!
625 
626     uno::Reference<lang::XMultiComponentFactory> xFactory(
627         mxComponentContext->getServiceManager() );
628 
629     if( xFactory.is() )
630     {
631         try
632 	{
633             // #i82460# try to retrieve special transition factory
634             mxOptionalTransitionFactory.set(
635                 xFactory->createInstanceWithContext(
636                     ::rtl::OUString::createFromAscii( "com.sun.star.presentation.TransitionFactory" ),
637                     mxComponentContext ),
638                 uno::UNO_QUERY );
639         }
640         catch (loader::CannotActivateFactoryException const&)
641 	{
642 	}
643     }
644 
645     mpListener.reset( new SeparateListenerImpl(
646                           *this,
647                           maScreenUpdater,
648                           maEventQueue ));
649     maEventMultiplexer.addSlideAnimationsEndHandler( mpListener );
650     maEventMultiplexer.addViewRepaintHandler( mpListener );
651     maEventMultiplexer.addHyperlinkHandler( mpListener, 0.0 );
652 	maEventMultiplexer.addAnimationStartHandler( mpListener );
653 	maEventMultiplexer.addAnimationEndHandler( mpListener );
654 }
655 
656 // we are about to be disposed (someone call dispose() on us)
disposing()657 void SlideShowImpl::disposing()
658 {
659     osl::MutexGuard const guard( m_aMutex );
660 
661     maEffectRewinder.dispose();
662 
663 	// stop slide transition sound, if any:
664     stopSlideTransitionSound();
665 
666     mxComponentContext.clear();
667 
668     if( mpCurrentSlideTransitionSound )
669     {
670         mpCurrentSlideTransitionSound->dispose();
671         mpCurrentSlideTransitionSound.reset();
672     }
673 
674     mpWaitSymbol.reset();
675 
676     if( mpRehearseTimingsActivity )
677     {
678         mpRehearseTimingsActivity->dispose();
679         mpRehearseTimingsActivity.reset();
680     }
681 
682     if( mpListener )
683     {
684         maEventMultiplexer.removeSlideAnimationsEndHandler(mpListener);
685         maEventMultiplexer.removeViewRepaintHandler(mpListener);
686         maEventMultiplexer.removeHyperlinkHandler(mpListener);
687 		maEventMultiplexer.removeAnimationStartHandler( mpListener );
688 		maEventMultiplexer.removeAnimationEndHandler( mpListener );
689 
690         mpListener.reset();
691     }
692 
693     maUserEventQueue.clear();
694     maActivitiesQueue.clear();
695     maEventMultiplexer.clear();
696     maEventQueue.clear();
697     mpPresTimer.reset();
698     maShapeCursors.clear();
699     maShapeEventListeners.clear();
700 
701     // send all listeners a disposing() that we are going down:
702     maListenerContainer.disposeAndClear(
703         lang::EventObject( static_cast<cppu::OWeakObject *>(this) ) );
704 
705     maViewContainer.dispose();
706 
707     // release slides:
708     mxPrefetchAnimationNode.clear();
709     mxPrefetchSlide.clear();
710     mpPrefetchSlide.reset();
711     mpCurrentSlide.reset();
712     mpPreviousSlide.reset();
713 }
714 
715 // stops the current slide transition sound
stopSlideTransitionSound()716 void SlideShowImpl::stopSlideTransitionSound()
717 {
718     if (mpCurrentSlideTransitionSound)
719     {
720         mpCurrentSlideTransitionSound->stopPlayback();
721         mpCurrentSlideTransitionSound->dispose();
722         mpCurrentSlideTransitionSound.reset();
723     }
724  }
725 
resetSlideTransitionSound(const uno::Any & rSound,bool bLoopSound)726 SoundPlayerSharedPtr SlideShowImpl::resetSlideTransitionSound( const uno::Any& rSound, bool bLoopSound )
727 {
728 	sal_Bool bStopSound = sal_False;
729 	rtl::OUString url;
730 
731 	if( !(rSound >>= bStopSound) )
732 		bStopSound = sal_False;
733 	rSound >>= url;
734 
735 	if( !bStopSound && (url.getLength() == 0) )
736 		return SoundPlayerSharedPtr();
737 
738 	stopSlideTransitionSound();
739 
740     if (url.getLength() > 0)
741     {
742         try
743         {
744             mpCurrentSlideTransitionSound = SoundPlayer::create(
745                 maEventMultiplexer, url, mxComponentContext );
746 			mpCurrentSlideTransitionSound->setPlaybackLoop( bLoopSound );
747         }
748         catch (lang::NoSupportException const&)
749         {
750             // catch possible exceptions from SoundPlayer, since
751             // being not able to playback the sound is not a hard
752             // error here (still, the slide transition should be
753             // shown).
754         }
755     }
756     return mpCurrentSlideTransitionSound;
757 }
758 
createSlideTransition(const uno::Reference<drawing::XDrawPage> & xDrawPage,const SlideSharedPtr & rLeavingSlide,const SlideSharedPtr & rEnteringSlide,const EventSharedPtr & rTransitionEndEvent)759 ActivitySharedPtr SlideShowImpl::createSlideTransition(
760     const uno::Reference< drawing::XDrawPage >& xDrawPage,
761     const SlideSharedPtr&                       rLeavingSlide,
762     const SlideSharedPtr&                       rEnteringSlide,
763     const EventSharedPtr&                       rTransitionEndEvent)
764 {
765     ENSURE_OR_THROW( !maViewContainer.empty(),
766                       "createSlideTransition(): No views" );
767     ENSURE_OR_THROW( rEnteringSlide,
768                       "createSlideTransition(): No entering slide" );
769 
770     // return empty transition, if slide transitions
771     // are disabled.
772     if (mbNoSlideTransitions)
773         return ActivitySharedPtr();
774 
775     // retrieve slide change parameters from XDrawPage
776     uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
777                                                     uno::UNO_QUERY );
778 
779     if( !xPropSet.is() )
780     {
781         OSL_TRACE( "createSlideTransition(): "
782                    "Slide has no PropertySet - assuming no transition\n" );
783         return ActivitySharedPtr();
784     }
785 
786     sal_Int16 nTransitionType(0);
787     if( !getPropertyValue( nTransitionType,
788                            xPropSet,
789                            OUSTR("TransitionType" )) )
790     {
791         OSL_TRACE( "createSlideTransition(): "
792                    "Could not extract slide transition type from XDrawPage - assuming no transition\n" );
793         return ActivitySharedPtr();
794     }
795 
796     sal_Int16 nTransitionSubType(0);
797     if( !getPropertyValue( nTransitionSubType,
798                            xPropSet,
799                            OUSTR("TransitionSubtype" )) )
800     {
801         OSL_TRACE( "createSlideTransition(): "
802                    "Could not extract slide transition subtype from XDrawPage - assuming no transition\n" );
803         return ActivitySharedPtr();
804     }
805 
806     bool bTransitionDirection(false);
807     if( !getPropertyValue( bTransitionDirection,
808                            xPropSet,
809                            OUSTR("TransitionDirection")) )
810     {
811         OSL_TRACE( "createSlideTransition(): "
812                    "Could not extract slide transition direction from XDrawPage - assuming default direction\n" );
813     }
814 
815     sal_Int32 aUnoColor(0);
816     if( !getPropertyValue( aUnoColor,
817                            xPropSet,
818                            OUSTR("TransitionFadeColor")) )
819     {
820         OSL_TRACE( "createSlideTransition(): "
821                    "Could not extract slide transition fade color from XDrawPage - assuming black\n" );
822     }
823 
824     const RGBColor aTransitionFadeColor( unoColor2RGBColor( aUnoColor ));
825 
826 	uno::Any aSound;
827 	sal_Bool bLoopSound = sal_False;
828 
829 	if( !getPropertyValue( aSound, xPropSet, OUSTR("Sound")) )
830 		OSL_TRACE( "createSlideTransition(): Could not determine transition sound effect URL from XDrawPage - using no sound\n" );
831 
832 	if( !getPropertyValue( bLoopSound, xPropSet, OUSTR("LoopSound") ) )
833 		OSL_TRACE( "createSlideTransition(): Could not get slide property 'LoopSound' - using no sound\n" );
834 
835     NumberAnimationSharedPtr pTransition(
836         TransitionFactory::createSlideTransition(
837             rLeavingSlide,
838             rEnteringSlide,
839             maViewContainer,
840             maScreenUpdater,
841             maEventMultiplexer,
842             mxOptionalTransitionFactory,
843             nTransitionType,
844             nTransitionSubType,
845             bTransitionDirection,
846             aTransitionFadeColor,
847             resetSlideTransitionSound( aSound, bLoopSound ) ));
848 
849     if( !pTransition )
850         return ActivitySharedPtr(); // no transition effect has been
851                                     // generated. Normally, that means
852                                     // that simply no transition is
853                                     // set on this slide.
854 
855     double nTransitionDuration(0.0);
856     if( !getPropertyValue( nTransitionDuration,
857                            xPropSet,
858                            OUSTR("TransitionDuration")) )
859     {
860         OSL_TRACE( "createSlideTransition(): "
861                    "Could not extract slide transition duration from XDrawPage - assuming no transition\n" );
862         return ActivitySharedPtr();
863     }
864 
865     sal_Int32 nMinFrames(5);
866     if( !getPropertyValue( nMinFrames,
867                            xPropSet,
868                            OUSTR("MinimalFrameNumber")) )
869     {
870         OSL_TRACE( "createSlideTransition(): "
871                    "No minimal number of frames given - assuming 5\n" );
872     }
873 
874     // prefetch slide transition bitmaps, but postpone it after
875     // displaySlide() has finished - sometimes, view size has not yet
876     // reached final size
877     maEventQueue.addEvent(
878         makeEvent(
879             boost::bind(
880                 &::slideshow::internal::Animation::prefetch,
881                 pTransition,
882                 AnimatableShapeSharedPtr(),
883                 ShapeAttributeLayerSharedPtr()),
884             "Animation::prefetch"));
885 
886     return ActivitySharedPtr(
887         ActivitiesFactory::createSimpleActivity(
888             ActivitiesFactory::CommonParameters(
889                 rTransitionEndEvent,
890                 maEventQueue,
891                 maActivitiesQueue,
892                 nTransitionDuration,
893                 nMinFrames,
894                 false,
895                 boost::optional<double>(1.0),
896                 0.0,
897                 0.0,
898                 ShapeSharedPtr(),
899                 rEnteringSlide->getSlideSize() ),
900             pTransition,
901             true ));
902 }
903 
findPolygons(uno::Reference<drawing::XDrawPage> const & xDrawPage)904 PolygonMap::iterator SlideShowImpl::findPolygons( uno::Reference<drawing::XDrawPage> const& xDrawPage)
905 {
906     // TODO(P2) : Optimize research in the map.
907     bool bFound = false;
908     PolygonMap::iterator aIter=maPolygons.begin();
909 
910 
911     while(aIter!=maPolygons.end() && !bFound)
912     {
913         if(aIter->first == xDrawPage)
914             bFound = true;
915         else
916             aIter++;
917     }
918 
919     return aIter;
920 }
921 
makeSlide(uno::Reference<drawing::XDrawPage> const & xDrawPage,uno::Reference<drawing::XDrawPagesSupplier> const & xDrawPages,uno::Reference<animations::XAnimationNode> const & xRootNode)922 SlideSharedPtr SlideShowImpl::makeSlide(
923     uno::Reference<drawing::XDrawPage> const&          xDrawPage,
924     uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
925     uno::Reference<animations::XAnimationNode> const&  xRootNode )
926 {
927     if( !xDrawPage.is() )
928         return SlideSharedPtr();
929 
930     // Retrieve polygons for the current slide
931     PolygonMap::iterator aIter;
932     aIter = findPolygons(xDrawPage);
933 
934     const SlideSharedPtr pSlide( createSlide(xDrawPage,
935                                              xDrawPages,
936                                              xRootNode,
937                                              maEventQueue,
938                                              maEventMultiplexer,
939                                              maScreenUpdater,
940                                              maActivitiesQueue,
941                                              maUserEventQueue,
942                                              *this,
943                                              maViewContainer,
944                                              mxComponentContext,
945                                              maShapeEventListeners,
946                                              maShapeCursors,
947                                              (aIter != maPolygons.end()) ? aIter->second : PolyPolygonVector(),
948                                              maUserPaintColor ? *maUserPaintColor : RGBColor(),
949 											 maUserPaintStrokeWidth,
950                                              !!maUserPaintColor,
951                                              mbImageAnimationsAllowed,
952                                              mbDisableAnimationZOrder) );
953 
954     // prefetch show content (reducing latency for slide
955     // bitmap and effect start later on)
956     pSlide->prefetch();
957 
958     return pSlide;
959 }
960 
requestWaitSymbol(void)961 void SlideShowImpl::requestWaitSymbol (void)
962 {
963     ++mnWaitSymbolRequestCount;
964     OSL_ASSERT(mnWaitSymbolRequestCount>0);
965 
966     if (mnWaitSymbolRequestCount == 1)
967     {
968         if( !mpWaitSymbol )
969         {
970             // fall back to cursor
971             requestCursor(calcActiveCursor(mnCurrentCursor));
972         }
973         else
974             mpWaitSymbol->show();
975     }
976 }
977 
releaseWaitSymbol(void)978 void SlideShowImpl::releaseWaitSymbol (void)
979 {
980     --mnWaitSymbolRequestCount;
981     OSL_ASSERT(mnWaitSymbolRequestCount>=0);
982 
983     if (mnWaitSymbolRequestCount == 0)
984     {
985         if( !mpWaitSymbol )
986         {
987             // fall back to cursor
988             requestCursor(calcActiveCursor(mnCurrentCursor));
989         }
990         else
991             mpWaitSymbol->hide();
992     }
993 }
994 
calcActiveCursor(sal_Int16 nCursorShape) const995 sal_Int16 SlideShowImpl::calcActiveCursor( sal_Int16 nCursorShape ) const
996 {
997     if( mnWaitSymbolRequestCount>0 && !mpWaitSymbol ) // enforce wait cursor
998         nCursorShape = awt::SystemPointer::WAIT;
999     else if( !mbMouseVisible ) // enforce INVISIBLE
1000         nCursorShape = awt::SystemPointer::INVISIBLE;
1001     else if( maUserPaintColor &&
1002              nCursorShape == awt::SystemPointer::ARROW )
1003         nCursorShape = awt::SystemPointer::PEN;
1004 
1005     return nCursorShape;
1006 }
1007 
1008 
stopShow()1009 void SlideShowImpl::stopShow()
1010 {
1011     // Force-end running animation
1012     // ===========================
1013     if (mpCurrentSlide)
1014     {
1015         mpCurrentSlide->hide();
1016         // Register polygons in the map
1017         if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1018             maPolygons.erase(mpCurrentSlide->getXDrawPage());
1019 
1020         maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1021     }
1022 
1023     // clear all queues
1024     maEventQueue.clear();
1025     maActivitiesQueue.clear();
1026 
1027     // Attention: we MUST clear the user event queue here,
1028     // this is because the current slide might have registered
1029     // shape events (click or enter/leave), which might
1030     // otherwise dangle forever in the queue (because of the
1031     // shared ptr nature). If someone needs to change this:
1032     // somehow unregister those shapes at the user event queue
1033     // on notifySlideEnded().
1034     maUserEventQueue.clear();
1035 
1036     // re-enable automatic effect advancement
1037     // (maEventQueue.clear() above might have killed
1038     // maEventMultiplexer's tick events)
1039     if (mbAutomaticAdvancementMode)
1040     {
1041         // toggle automatic mode (enabling just again is
1042         // ignored by EventMultiplexer)
1043         maEventMultiplexer.setAutomaticMode( false );
1044         maEventMultiplexer.setAutomaticMode( true );
1045     }
1046 }
1047 
1048 
1049 
1050 class SlideShowImpl::PrefetchPropertiesFunc
1051 {
1052 public:
PrefetchPropertiesFunc(SlideShowImpl * that_,bool & rbSkipAllMainSequenceEffects,bool & rbSkipSlideTransition)1053     PrefetchPropertiesFunc( SlideShowImpl * that_,
1054         bool& rbSkipAllMainSequenceEffects,
1055         bool& rbSkipSlideTransition)
1056         : mpSlideShowImpl(that_),
1057           mrbSkipAllMainSequenceEffects(rbSkipAllMainSequenceEffects),
1058           mrbSkipSlideTransition(rbSkipSlideTransition)
1059     {}
1060 
operator ()(beans::PropertyValue const & rProperty) const1061     void operator()( beans::PropertyValue const& rProperty ) const {
1062         if (rProperty.Name.equalsAsciiL(
1063                 RTL_CONSTASCII_STRINGPARAM("Prefetch") ))
1064         {
1065             uno::Sequence<uno::Any> seq;
1066             if ((rProperty.Value >>= seq) && seq.getLength() == 2)
1067             {
1068                 seq[0] >>= mpSlideShowImpl->mxPrefetchSlide;
1069                 seq[1] >>= mpSlideShowImpl->mxPrefetchAnimationNode;
1070             }
1071         }
1072         else if (rProperty.Name.equalsAsciiL(
1073                 RTL_CONSTASCII_STRINGPARAM("SkipAllMainSequenceEffects") ))
1074         {
1075             rProperty.Value >>= mrbSkipAllMainSequenceEffects;
1076         }
1077         else if (rProperty.Name.equalsAsciiL(
1078                 RTL_CONSTASCII_STRINGPARAM("SkipSlideTransition") ))
1079         {
1080             rProperty.Value >>= mrbSkipSlideTransition;
1081         }
1082         else
1083         {
1084             OSL_ENSURE( false, rtl::OUStringToOString(
1085                             rProperty.Name, RTL_TEXTENCODING_UTF8 ).getStr() );
1086         }
1087     }
1088 private:
1089     SlideShowImpl *const mpSlideShowImpl;
1090     bool& mrbSkipAllMainSequenceEffects;
1091     bool& mrbSkipSlideTransition;
1092 };
1093 
displaySlide(uno::Reference<drawing::XDrawPage> const & xSlide,uno::Reference<drawing::XDrawPagesSupplier> const & xDrawPages,uno::Reference<animations::XAnimationNode> const & xRootNode,uno::Sequence<beans::PropertyValue> const & rProperties)1094 void SlideShowImpl::displaySlide(
1095     uno::Reference<drawing::XDrawPage> const& xSlide,
1096     uno::Reference<drawing::XDrawPagesSupplier> const& xDrawPages,
1097     uno::Reference<animations::XAnimationNode> const& xRootNode,
1098     uno::Sequence<beans::PropertyValue> const& rProperties )
1099     throw (uno::RuntimeException)
1100 {
1101     osl::MutexGuard const guard( m_aMutex );
1102 
1103     if (isDisposed())
1104         return;
1105 
1106     maEffectRewinder.setRootAnimationNode(xRootNode);
1107 
1108     // precondition: must only be called from the main thread!
1109     DBG_TESTSOLARMUTEX();
1110 
1111     mxDrawPagesSupplier = xDrawPages;
1112 
1113     stopShow(); // MUST call that: results in
1114     // maUserEventQueue.clear(). What's more,
1115     // stopShow()'s currSlide->hide() call is
1116     // now also required, notifySlideEnded()
1117     // relies on that
1118     // unconditionally. Otherwise, genuine
1119     // shape animations (drawing layer and
1120     // GIF) will not be stopped.
1121 
1122     bool bSkipAllMainSequenceEffects (false);
1123     bool bSkipSlideTransition (false);
1124     std::for_each( rProperties.getConstArray(),
1125                    rProperties.getConstArray() + rProperties.getLength(),
1126         PrefetchPropertiesFunc(this, bSkipAllMainSequenceEffects, bSkipSlideTransition) );
1127 
1128     OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1129     if (maViewContainer.empty())
1130         return;
1131 
1132     // this here might take some time
1133     {
1134         WaitSymbolLock aLock (*this);
1135 
1136         mpPreviousSlide = mpCurrentSlide;
1137         mpCurrentSlide.reset();
1138 
1139         if (matches( mpPrefetchSlide, xSlide, xRootNode ))
1140         {
1141             // prefetched slide matches:
1142             mpCurrentSlide = mpPrefetchSlide;
1143         }
1144         else
1145             mpCurrentSlide = makeSlide( xSlide, xDrawPages, xRootNode );
1146 
1147         OSL_ASSERT( mpCurrentSlide );
1148         if (mpCurrentSlide)
1149         {
1150             basegfx::B2DSize oldSlideSize;
1151             if( mpPreviousSlide )
1152                 oldSlideSize = mpPreviousSlide->getSlideSize();
1153 
1154             basegfx::B2DSize const slideSize( mpCurrentSlide->getSlideSize() );
1155 
1156             // push new transformation to all views, if size changed
1157             if( !mpPreviousSlide || oldSlideSize != slideSize )
1158             {
1159                 std::for_each( maViewContainer.begin(),
1160                                maViewContainer.end(),
1161                                boost::bind( &View::setViewSize, _1,
1162                                             boost::cref(slideSize) ));
1163 
1164                 // explicitly notify view change here,
1165                 // because transformation might have changed:
1166                 // optimization, this->notifyViewChange() would
1167                 // repaint slide which is not necessary.
1168                 maEventMultiplexer.notifyViewsChanged();
1169             }
1170 
1171             // create slide transition, and add proper end event
1172             // (which then starts the slide effects
1173             // via CURRENT_SLIDE.show())
1174             ActivitySharedPtr pSlideChangeActivity (
1175                 createSlideTransition(
1176                     mpCurrentSlide->getXDrawPage(),
1177                     mpPreviousSlide,
1178                     mpCurrentSlide,
1179                     makeEvent(
1180                         boost::bind(
1181                             &SlideShowImpl::notifySlideTransitionEnded,
1182                             this,
1183                             false ),
1184                         "SlideShowImpl::notifySlideTransitionEnded")));
1185 
1186             if (bSkipSlideTransition)
1187             {
1188                 // The transition activity was created for the side effects
1189                 // (like sound transitions). Because we want to skip the
1190                 // actual transition animation we do not need the activity
1191                 // anymore.
1192                 pSlideChangeActivity.reset();
1193             }
1194 
1195             if (pSlideChangeActivity)
1196             {
1197                 // factory generated a slide transition - activate it!
1198                 maActivitiesQueue.addActivity( pSlideChangeActivity );
1199             }
1200             else
1201             {
1202                 // no transition effect on this slide - schedule slide
1203                 // effect start event right away.
1204                 maEventQueue.addEvent(
1205                     makeEvent(
1206                         boost::bind(
1207                             &SlideShowImpl::notifySlideTransitionEnded,
1208                             this,
1209                             true ),
1210                         "SlideShowImpl::notifySlideTransitionEnded"));
1211             }
1212         }
1213     } // finally
1214 
1215     maEventMultiplexer.notifySlideTransitionStarted();
1216     maListenerContainer.forEach<presentation::XSlideShowListener>(
1217         boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1218 
1219     // We are currently rewinding an effect. This lead us from the next
1220     // slide to this one. To complete this we have to play back all main
1221     // sequence effects on this slide.
1222     if (bSkipAllMainSequenceEffects)
1223         maEffectRewinder.skipAllMainSequenceEffects();
1224 }
1225 
redisplayCurrentSlide(void)1226 void SlideShowImpl::redisplayCurrentSlide (void)
1227 {
1228     osl::MutexGuard const guard( m_aMutex );
1229 
1230     if (isDisposed())
1231         return;
1232 
1233     // precondition: must only be called from the main thread!
1234     DBG_TESTSOLARMUTEX();
1235     stopShow();
1236 
1237     OSL_ENSURE( !maViewContainer.empty(), "### no views!" );
1238     if (maViewContainer.empty())
1239         return;
1240 
1241     // No transition effect on this slide - schedule slide
1242     // effect start event right away.
1243     maEventQueue.addEvent(
1244         makeEvent(
1245             boost::bind(
1246                 &SlideShowImpl::notifySlideTransitionEnded,
1247                 this,
1248                 true ),
1249             "SlideShowImpl::notifySlideTransitionEnded"));
1250 
1251     maEventMultiplexer.notifySlideTransitionStarted();
1252     maListenerContainer.forEach<presentation::XSlideShowListener>(
1253         boost::mem_fn( &presentation::XSlideShowListener::slideTransitionStarted ) );
1254 }
1255 
nextEffect()1256 sal_Bool SlideShowImpl::nextEffect() throw (uno::RuntimeException)
1257 {
1258     osl::MutexGuard const guard( m_aMutex );
1259 
1260     if (isDisposed())
1261         return false;
1262 
1263     // precondition: must only be called from the main thread!
1264     DBG_TESTSOLARMUTEX();
1265 
1266     if (mbShowPaused)
1267         return true;
1268     else
1269         return maEventMultiplexer.notifyNextEffect();
1270 }
1271 
1272 
previousEffect()1273 sal_Bool SlideShowImpl::previousEffect() throw (uno::RuntimeException)
1274 {
1275     osl::MutexGuard const guard( m_aMutex );
1276 
1277     if (isDisposed())
1278         return false;
1279 
1280     // precondition: must only be called from the main thread!
1281     DBG_TESTSOLARMUTEX();
1282 
1283     if (mbShowPaused)
1284         return true;
1285     else
1286     {
1287         return maEffectRewinder.rewind(
1288             maScreenUpdater.createLock(false),
1289             ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::redisplayCurrentSlide), this),
1290             ::boost::bind<void>(::boost::mem_fn(&SlideShowImpl::rewindEffectToPreviousSlide), this));
1291     }
1292 }
1293 
rewindEffectToPreviousSlide(void)1294 void SlideShowImpl::rewindEffectToPreviousSlide (void)
1295 {
1296     // Show the wait symbol now and prevent it from showing temporary slide
1297     // content while effects are played back.
1298     WaitSymbolLock aLock (*this);
1299 
1300     // A previous call to EffectRewinder::Rewind could not rewind the current
1301     // effect because there are no effects on the current slide or none has
1302     // yet been displayed. Go to the previous slide.
1303     notifySlideEnded(true);
1304 
1305     // Process pending events once more in order to have the following
1306     // screen update show the last effect. Not sure whether this should be
1307     // necessary.
1308     maEventQueue.forceEmpty();
1309 
1310     // We have to call the screen updater before the wait symbol is turned
1311     // off. Otherwise the wait symbol would force the display of an
1312     // intermediate state of the slide (before the effects are replayed.)
1313     maScreenUpdater.commitUpdates();
1314 }
1315 
startShapeActivity(uno::Reference<drawing::XShape> const &)1316 sal_Bool SlideShowImpl::startShapeActivity(
1317     uno::Reference<drawing::XShape> const& /*xShape*/ )
1318     throw (uno::RuntimeException)
1319 {
1320     osl::MutexGuard const guard( m_aMutex );
1321 
1322     // precondition: must only be called from the main thread!
1323     DBG_TESTSOLARMUTEX();
1324 
1325     // TODO(F3): NYI
1326     OSL_ENSURE( false, "not yet implemented!" );
1327     return false;
1328 }
1329 
stopShapeActivity(uno::Reference<drawing::XShape> const &)1330 sal_Bool SlideShowImpl::stopShapeActivity(
1331     uno::Reference<drawing::XShape> const& /*xShape*/ )
1332     throw (uno::RuntimeException)
1333 {
1334     osl::MutexGuard const guard( m_aMutex );
1335 
1336     // precondition: must only be called from the main thread!
1337     DBG_TESTSOLARMUTEX();
1338 
1339     // TODO(F3): NYI
1340     OSL_ENSURE( false, "not yet implemented!" );
1341     return false;
1342 }
1343 
pause(sal_Bool bPauseShow)1344 sal_Bool SlideShowImpl::pause( sal_Bool bPauseShow )
1345     throw (uno::RuntimeException)
1346 {
1347     osl::MutexGuard const guard( m_aMutex );
1348 
1349     if (isDisposed())
1350         return false;
1351 
1352     // precondition: must only be called from the main thread!
1353     DBG_TESTSOLARMUTEX();
1354 
1355 
1356     if (bPauseShow)
1357         mpPresTimer->pauseTimer();
1358     else
1359         mpPresTimer->continueTimer();
1360 
1361     maEventMultiplexer.notifyPauseMode(bPauseShow);
1362 
1363     mbShowPaused = bPauseShow;
1364     return true;
1365 }
1366 
getCurrentSlide()1367 uno::Reference<drawing::XDrawPage> SlideShowImpl::getCurrentSlide()
1368     throw (uno::RuntimeException)
1369 {
1370     osl::MutexGuard const guard( m_aMutex );
1371 
1372     if (isDisposed())
1373         return uno::Reference<drawing::XDrawPage>();
1374 
1375     // precondition: must only be called from the main thread!
1376     DBG_TESTSOLARMUTEX();
1377 
1378     if (mpCurrentSlide)
1379         return mpCurrentSlide->getXDrawPage();
1380     else
1381         return uno::Reference<drawing::XDrawPage>();
1382 }
1383 
addView(uno::Reference<presentation::XSlideShowView> const & xView)1384 sal_Bool SlideShowImpl::addView(
1385     uno::Reference<presentation::XSlideShowView> const& xView )
1386     throw (uno::RuntimeException)
1387 {
1388     osl::MutexGuard const guard( m_aMutex );
1389 
1390     if (isDisposed())
1391         return false;
1392 
1393     // precondition: must only be called from the main thread!
1394     DBG_TESTSOLARMUTEX();
1395 
1396     // first of all, check if view has a valid canvas
1397     ENSURE_OR_RETURN_FALSE( xView.is(), "addView(): Invalid view" );
1398     ENSURE_OR_RETURN_FALSE( xView->getCanvas().is(),
1399                        "addView(): View does not provide a valid canvas" );
1400 
1401     UnoViewSharedPtr const pView( createSlideView(
1402                                       xView,
1403                                       maEventQueue,
1404                                       maEventMultiplexer ));
1405     if (!maViewContainer.addView( pView ))
1406         return false; // view already added
1407 
1408     // initialize view content
1409     // =======================
1410 
1411     if (mpCurrentSlide)
1412     {
1413         // set view transformation
1414         const basegfx::B2ISize slideSize = mpCurrentSlide->getSlideSize();
1415         pView->setViewSize( basegfx::B2DSize( slideSize.getX(),
1416                                               slideSize.getY() ) );
1417     }
1418 
1419     // clear view area (since its newly added,
1420     // we need a clean slate)
1421     pView->clearAll();
1422 
1423     // broadcast newly added view
1424     maEventMultiplexer.notifyViewAdded( pView );
1425 
1426     // set current mouse ptr
1427     pView->setCursorShape( calcActiveCursor(mnCurrentCursor) );
1428 
1429     return true;
1430 }
1431 
removeView(uno::Reference<presentation::XSlideShowView> const & xView)1432 sal_Bool SlideShowImpl::removeView(
1433     uno::Reference<presentation::XSlideShowView> const& xView )
1434     throw (uno::RuntimeException)
1435 {
1436     osl::MutexGuard const guard( m_aMutex );
1437 
1438     // precondition: must only be called from the main thread!
1439     DBG_TESTSOLARMUTEX();
1440 
1441     ENSURE_OR_RETURN_FALSE( xView.is(), "removeView(): Invalid view" );
1442 
1443     UnoViewSharedPtr const pView( maViewContainer.removeView( xView ) );
1444     if( !pView )
1445         return false; // view was not added in the first place
1446 
1447     // remove view from EventMultiplexer (mouse events etc.)
1448     maEventMultiplexer.notifyViewRemoved( pView );
1449 
1450     pView->_dispose();
1451 
1452     return true;
1453 }
1454 
registerUserPaintPolygons(const uno::Reference<lang::XMultiServiceFactory> & xDocFactory)1455 void SlideShowImpl::registerUserPaintPolygons( const uno::Reference< lang::XMultiServiceFactory >& xDocFactory ) throw (uno::RuntimeException)
1456 {
1457     // Retrieve Polygons if user ends presentation by context menu
1458     if (mpCurrentSlide)
1459     {
1460         if(findPolygons(mpCurrentSlide->getXDrawPage()) != maPolygons.end())
1461             maPolygons.erase(mpCurrentSlide->getXDrawPage());
1462 
1463         maPolygons.insert(make_pair(mpCurrentSlide->getXDrawPage(),mpCurrentSlide->getPolygons()));
1464     }
1465 
1466     // Creating the layer for shapes
1467     // query for the XLayerManager
1468     uno::Reference< drawing::XLayerSupplier > xLayerSupplier(xDocFactory, uno::UNO_QUERY);
1469     uno::Reference< container::XNameAccess > xNameAccess = xLayerSupplier->getLayerManager();
1470 
1471     uno::Reference< drawing::XLayerManager > xLayerManager(xNameAccess, uno::UNO_QUERY);
1472     // create a layer and set its properties
1473     uno::Reference< drawing::XLayer > xDrawnInSlideshow = xLayerManager->insertNewByIndex(xLayerManager->getCount());
1474     uno::Reference< beans::XPropertySet > xLayerPropSet(xDrawnInSlideshow, uno::UNO_QUERY);
1475 
1476     // Layer Name which enables to catch annotations
1477     rtl::OUString layerName = rtl::OUString::createFromAscii("DrawnInSlideshow");
1478     uno::Any aPropLayer;
1479 
1480     aPropLayer <<= layerName;
1481     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("Name"), aPropLayer);
1482 
1483     aPropLayer <<= true;
1484     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("IsVisible"), aPropLayer);
1485 
1486     aPropLayer <<= false;
1487     xLayerPropSet->setPropertyValue(rtl::OUString::createFromAscii("IsLocked"), aPropLayer);
1488 
1489     PolygonMap::iterator aIter=maPolygons.begin();
1490 
1491     PolyPolygonVector aPolygons;
1492     ::cppcanvas::PolyPolygonSharedPtr pPolyPoly;
1493     ::basegfx::B2DPolyPolygon b2DPolyPoly;
1494 
1495     // Register polygons for each slide
1496     while(aIter!=maPolygons.end())
1497     {
1498         aPolygons = aIter->second;
1499         // Get shapes for the slide
1500         ::com::sun::star::uno::Reference< ::com::sun::star::drawing::XShapes > Shapes(aIter->first, ::com::sun::star::uno::UNO_QUERY);
1501         // Retrieve polygons for one slide
1502         for( PolyPolygonVector::iterator aIterPoly=aPolygons.begin(),
1503                  aEnd=aPolygons.end();
1504              aIterPoly!=aEnd; ++aIterPoly )
1505         {
1506             pPolyPoly = (*aIterPoly);
1507             b2DPolyPoly = ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(pPolyPoly->getUNOPolyPolygon());
1508 
1509             // Normally there is only one polygon
1510             for(sal_uInt32 i=0; i< b2DPolyPoly.count();i++)
1511             {
1512                 const ::basegfx::B2DPolygon& aPoly = b2DPolyPoly.getB2DPolygon(i);
1513                 sal_uInt32 nPoints = aPoly.count();
1514 
1515                 if( nPoints > 1)
1516                 {
1517                     // create the PolyLineShape
1518                     uno::Reference< uno::XInterface > polyshape(xDocFactory->createInstance(
1519                                                                     rtl::OUString::createFromAscii("com.sun.star.drawing.PolyLineShape") ) );
1520                     uno::Reference< drawing::XShape > rPolyShape(polyshape, uno::UNO_QUERY);
1521 
1522                     // Add the shape to the slide
1523                     Shapes->add(rPolyShape);
1524 
1525                     // Retrieve shape properties
1526                     uno::Reference< beans::XPropertySet > aXPropSet = uno::Reference< beans::XPropertySet >( rPolyShape, uno::UNO_QUERY );
1527                     // Construct a sequence of points sequence
1528                     drawing::PointSequenceSequence aRetval;
1529                     // Create only one sequence for one polygon
1530                     aRetval.realloc( 1 );
1531                     // Retrieve the sequence of points from aRetval
1532                     drawing::PointSequence* pOuterSequence = aRetval.getArray();
1533                     // Create 2 points in this sequence
1534                     pOuterSequence->realloc(nPoints);
1535                     // Get these points which are in an array
1536                     awt::Point* pInnerSequence = pOuterSequence->getArray();
1537                     for( sal_uInt32 n = 0; n < nPoints; n++ )
1538                     {
1539                         // Create a point from the polygon
1540                         *pInnerSequence++ = awt::Point(
1541                             basegfx::fround(aPoly.getB2DPoint(n).getX()),
1542                             basegfx::fround(aPoly.getB2DPoint(n).getY()));
1543                     }
1544 
1545                     // Fill the properties
1546                     // Give the built PointSequenceSequence.
1547                     uno::Any aParam;
1548                     aParam <<= aRetval;
1549                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("PolyPolygon"), aParam );
1550 
1551                     // LineStyle : SOLID by default
1552                     uno::Any			aAny;
1553                     drawing::LineStyle	eLS;
1554                     eLS = drawing::LineStyle_SOLID;
1555                     aAny <<= eLS;
1556                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineStyle"), aAny );
1557 
1558                     // LineColor
1559                     sal_uInt32			nLineColor;
1560                     nLineColor = pPolyPoly->getRGBALineColor();
1561                     // Transform polygon color from RRGGBBAA to AARRGGBB
1562                     aAny <<= RGBAColor2UnoColor(nLineColor);
1563                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineColor"), aAny );
1564 
1565                     // LineWidth
1566                     double				fLineWidth;
1567                     fLineWidth = pPolyPoly->getStrokeWidth();
1568                     aAny <<= (sal_Int32)fLineWidth;
1569                     aXPropSet->setPropertyValue( rtl::OUString::createFromAscii("LineWidth"), aAny );
1570 
1571                     // make polygons special
1572                     xLayerManager->attachShapeToLayer(rPolyShape, xDrawnInSlideshow);
1573                 }
1574             }
1575         }
1576         ++aIter;
1577     }
1578 }
1579 
setProperty(beans::PropertyValue const & rProperty)1580 sal_Bool SlideShowImpl::setProperty( beans::PropertyValue const& rProperty )
1581     throw (uno::RuntimeException)
1582 {
1583     osl::MutexGuard const guard( m_aMutex );
1584 
1585     if (isDisposed())
1586         return false;
1587 
1588     // precondition: must only be called from the main thread!
1589     DBG_TESTSOLARMUTEX();
1590 
1591     if (rProperty.Name.equalsAsciiL(
1592             RTL_CONSTASCII_STRINGPARAM("AutomaticAdvancement") ))
1593     {
1594         double nTimeout(0.0);
1595         mbAutomaticAdvancementMode = (rProperty.Value >>= nTimeout);
1596         if (mbAutomaticAdvancementMode)
1597         {
1598             maEventMultiplexer.setAutomaticTimeout( nTimeout );
1599         }
1600         maEventMultiplexer.setAutomaticMode( mbAutomaticAdvancementMode );
1601         return true;
1602     }
1603 
1604     if (rProperty.Name.equalsAsciiL(
1605             RTL_CONSTASCII_STRINGPARAM("UserPaintColor") ))
1606     {
1607         sal_Int32 nColor(0);
1608         if (rProperty.Value >>= nColor)
1609         {
1610             OSL_ENSURE( mbMouseVisible,
1611                         "setProperty(): User paint overrides invisible mouse" );
1612 
1613             // enable user paint
1614             maUserPaintColor.reset( unoColor2RGBColor( nColor ) );
1615 			if( mpCurrentSlide && !mpCurrentSlide->isPaintOverlayActive() )
1616 				mpCurrentSlide->enablePaintOverlay();
1617 
1618 			maEventMultiplexer.notifyUserPaintColor( *maUserPaintColor );
1619         }
1620         else
1621         {
1622             // disable user paint
1623             maUserPaintColor.reset();
1624             maEventMultiplexer.notifyUserPaintDisabled();
1625 			if( mpCurrentSlide )
1626 				mpCurrentSlide->disablePaintOverlay();
1627         }
1628 
1629         resetCursor();
1630 
1631         return true;
1632     }
1633 
1634 	// adding support for erasing features in UserPaintOverlay
1635 	if (rProperty.Name.equalsAsciiL(
1636             RTL_CONSTASCII_STRINGPARAM("EraseAllInk") ))
1637 	{
1638 		bool nEraseAllInk(false);
1639 		if (rProperty.Value >>= nEraseAllInk)
1640 		{
1641 		    OSL_ENSURE( mbMouseVisible,
1642                         "setProperty(): User paint overrides invisible mouse" );
1643 
1644 		    // enable user paint
1645 		    maEraseAllInk.reset( nEraseAllInk );
1646 		    maEventMultiplexer.notifyEraseAllInk( *maEraseAllInk );
1647 	    }
1648 
1649 	    return true;
1650 	}
1651 
1652 	if (rProperty.Name.equalsAsciiL(
1653             RTL_CONSTASCII_STRINGPARAM("SwitchPenMode") ))
1654 	{
1655 		bool nSwitchPenMode(false);
1656 		if (rProperty.Value >>= nSwitchPenMode)
1657 		{
1658 		    OSL_ENSURE( mbMouseVisible,
1659                         "setProperty(): User paint overrides invisible mouse" );
1660 
1661 		    if(nSwitchPenMode == true){
1662 			// Switch to Pen Mode
1663 			maSwitchPenMode.reset( nSwitchPenMode );
1664 			maEventMultiplexer.notifySwitchPenMode();
1665 		    }
1666 		}
1667 		return true;
1668 	}
1669 
1670 
1671 	if (rProperty.Name.equalsAsciiL(
1672             RTL_CONSTASCII_STRINGPARAM("SwitchEraserMode") ))
1673 	{
1674 		bool nSwitchEraserMode(false);
1675 		if (rProperty.Value >>= nSwitchEraserMode)
1676 		{
1677 		    OSL_ENSURE( mbMouseVisible,
1678                         "setProperty(): User paint overrides invisible mouse" );
1679 		    if(nSwitchEraserMode == true){
1680 			// switch to Eraser mode
1681 			maSwitchEraserMode.reset( nSwitchEraserMode );
1682 			maEventMultiplexer.notifySwitchEraserMode();
1683 		    }
1684 		}
1685 
1686 		return true;
1687 	}
1688 
1689 
1690 
1691 	if (rProperty.Name.equalsAsciiL(
1692             RTL_CONSTASCII_STRINGPARAM("EraseInk") ))
1693 	{
1694 		sal_Int32 nEraseInk(100);
1695 		if (rProperty.Value >>= nEraseInk)
1696 		{
1697 		    OSL_ENSURE( mbMouseVisible,
1698                         "setProperty(): User paint overrides invisible mouse" );
1699 
1700 		    // enable user paint
1701 		    maEraseInk.reset( nEraseInk );
1702 		    maEventMultiplexer.notifyEraseInkWidth( *maEraseInk );
1703 		}
1704 
1705 		return true;
1706 	}
1707 
1708 	// new Property for pen's width
1709     if (rProperty.Name.equalsAsciiL(
1710             RTL_CONSTASCII_STRINGPARAM("UserPaintStrokeWidth") ))
1711     {
1712         double nWidth(4.0);
1713         if (rProperty.Value >>= nWidth)
1714         {
1715             OSL_ENSURE( mbMouseVisible,"setProperty(): User paint overrides invisible mouse" );
1716             // enable user paint stroke width
1717             maUserPaintStrokeWidth = nWidth;
1718             maEventMultiplexer.notifyUserPaintStrokeWidth( maUserPaintStrokeWidth );
1719         }
1720 
1721         return true;
1722     }
1723 
1724     if (rProperty.Name.equalsAsciiL(
1725             RTL_CONSTASCII_STRINGPARAM("AdvanceOnClick") ))
1726     {
1727         sal_Bool bAdvanceOnClick = sal_False;
1728         if (! (rProperty.Value >>= bAdvanceOnClick))
1729             return false;
1730         maUserEventQueue.setAdvanceOnClick( bAdvanceOnClick );
1731         return true;
1732     }
1733 
1734     if (rProperty.Name.equalsAsciiL(
1735             RTL_CONSTASCII_STRINGPARAM("DisableAnimationZOrder") ))
1736     {
1737         sal_Bool bDisableAnimationZOrder = sal_False;
1738         if (! (rProperty.Value >>= bDisableAnimationZOrder))
1739             return false;
1740         mbDisableAnimationZOrder = bDisableAnimationZOrder == sal_True;
1741         return true;
1742     }
1743 
1744     if (rProperty.Name.equalsAsciiL(
1745             RTL_CONSTASCII_STRINGPARAM("ImageAnimationsAllowed") ) )
1746     {
1747         if (! (rProperty.Value >>= mbImageAnimationsAllowed))
1748             return false;
1749 
1750         // TODO(F3): Forward to slides!
1751 //         if( bOldValue != mbImageAnimationsAllowed )
1752 //         {
1753 //             if( mbImageAnimationsAllowed )
1754 //                 maEventMultiplexer.notifyIntrinsicAnimationsEnabled();
1755 //             else
1756 //                 maEventMultiplexer.notifyIntrinsicAnimationsDisabled();
1757 //         }
1758 
1759         return true;
1760     }
1761 
1762     if (rProperty.Name.equalsAsciiL(
1763             RTL_CONSTASCII_STRINGPARAM("MouseVisible") ))
1764     {
1765         if (! (rProperty.Value >>= mbMouseVisible))
1766             return false;
1767 
1768         requestCursor(mnCurrentCursor);
1769 
1770         return true;
1771     }
1772 
1773     if (rProperty.Name.equalsAsciiL(
1774             RTL_CONSTASCII_STRINGPARAM("ForceManualAdvance") ))
1775     {
1776         return (rProperty.Value >>= mbForceManualAdvance);
1777     }
1778 
1779     if (rProperty.Name.equalsAsciiL(
1780             RTL_CONSTASCII_STRINGPARAM("RehearseTimings") ))
1781     {
1782         bool bRehearseTimings = false;
1783         if (! (rProperty.Value >>= bRehearseTimings))
1784             return false;
1785 
1786         if (bRehearseTimings)
1787         {
1788             // TODO(Q3): Move to slide
1789             mpRehearseTimingsActivity = RehearseTimingsActivity::create(
1790                 SlideShowContext(
1791                     mpDummyPtr,
1792                     maEventQueue,
1793                     maEventMultiplexer,
1794                     maScreenUpdater,
1795                     maActivitiesQueue,
1796                     maUserEventQueue,
1797                     *this,
1798                     maViewContainer,
1799                     mxComponentContext) );
1800         }
1801         else if (mpRehearseTimingsActivity)
1802         {
1803             // removes timer from all views:
1804             mpRehearseTimingsActivity->dispose();
1805             mpRehearseTimingsActivity.reset();
1806         }
1807         return true;
1808     }
1809 
1810     if (rProperty.Name.equalsAsciiL(
1811             RTL_CONSTASCII_STRINGPARAM("WaitSymbolBitmap") ))
1812     {
1813         uno::Reference<rendering::XBitmap> xBitmap;
1814         if (! (rProperty.Value >>= xBitmap))
1815             return false;
1816 
1817         mpWaitSymbol = WaitSymbol::create( xBitmap,
1818                                            maScreenUpdater,
1819                                            maEventMultiplexer,
1820                                            maViewContainer );
1821 
1822         return true;
1823     }
1824 
1825     if (rProperty.Name.equalsAsciiL(
1826             RTL_CONSTASCII_STRINGPARAM("NoSlideTransitions") ))
1827     {
1828         return (rProperty.Value >>= mbNoSlideTransitions);
1829     }
1830 
1831     if (rProperty.Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("IsSoundEnabled")))
1832     {
1833         uno::Sequence<uno::Any> aValues;
1834         uno::Reference<presentation::XSlideShowView> xView;
1835         sal_Bool bValue (false);
1836         if ((rProperty.Value >>= aValues)
1837             && aValues.getLength()==2
1838             && (aValues[0] >>= xView)
1839             && (aValues[1] >>= bValue))
1840         {
1841             // Look up the view.
1842             for (UnoViewVector::const_iterator
1843                      iView (maViewContainer.begin()),
1844                      iEnd (maViewContainer.end());
1845                  iView!=iEnd;
1846                  ++iView)
1847             {
1848                 if (*iView && (*iView)->getUnoView()==xView)
1849                 {
1850                     // Store the flag at the view so that media shapes have
1851                     // access to it.
1852                     (*iView)->setIsSoundEnabled(bValue);
1853                     return true;
1854                 }
1855             }
1856         }
1857     }
1858 
1859     return false;
1860 }
1861 
addSlideShowListener(uno::Reference<presentation::XSlideShowListener> const & xListener)1862 void SlideShowImpl::addSlideShowListener(
1863     uno::Reference<presentation::XSlideShowListener> const& xListener )
1864     throw (uno::RuntimeException)
1865 {
1866     osl::MutexGuard const guard( m_aMutex );
1867 
1868     if (isDisposed())
1869         return;
1870 
1871     // container syncs with passed mutex ref
1872     maListenerContainer.addInterface(xListener);
1873 }
1874 
removeSlideShowListener(uno::Reference<presentation::XSlideShowListener> const & xListener)1875 void SlideShowImpl::removeSlideShowListener(
1876     uno::Reference<presentation::XSlideShowListener> const& xListener )
1877     throw (uno::RuntimeException)
1878 {
1879     osl::MutexGuard const guard( m_aMutex );
1880 
1881     // container syncs with passed mutex ref
1882     maListenerContainer.removeInterface(xListener);
1883 }
1884 
addShapeEventListener(uno::Reference<presentation::XShapeEventListener> const & xListener,uno::Reference<drawing::XShape> const & xShape)1885 void SlideShowImpl::addShapeEventListener(
1886     uno::Reference<presentation::XShapeEventListener> const& xListener,
1887     uno::Reference<drawing::XShape> const& xShape )
1888     throw (uno::RuntimeException)
1889 {
1890     osl::MutexGuard const guard( m_aMutex );
1891 
1892     if (isDisposed())
1893         return;
1894 
1895     // precondition: must only be called from the main thread!
1896     DBG_TESTSOLARMUTEX();
1897 
1898     ShapeEventListenerMap::iterator aIter;
1899     if( (aIter=maShapeEventListeners.find( xShape )) ==
1900         maShapeEventListeners.end() )
1901     {
1902         // no entry for this shape -> create one
1903         aIter = maShapeEventListeners.insert(
1904             ShapeEventListenerMap::value_type(
1905                 xShape,
1906                 boost::shared_ptr<cppu::OInterfaceContainerHelper>(
1907                     new cppu::OInterfaceContainerHelper(m_aMutex)))).first;
1908     }
1909 
1910     // add new listener to broadcaster
1911     if( aIter->second.get() )
1912         aIter->second->addInterface( xListener );
1913 
1914     maEventMultiplexer.notifyShapeListenerAdded(xListener,
1915                                                 xShape);
1916 }
1917 
removeShapeEventListener(uno::Reference<presentation::XShapeEventListener> const & xListener,uno::Reference<drawing::XShape> const & xShape)1918 void SlideShowImpl::removeShapeEventListener(
1919     uno::Reference<presentation::XShapeEventListener> const& xListener,
1920     uno::Reference<drawing::XShape> const& xShape )
1921     throw (uno::RuntimeException)
1922 {
1923     osl::MutexGuard const guard( m_aMutex );
1924 
1925     // precondition: must only be called from the main thread!
1926     DBG_TESTSOLARMUTEX();
1927 
1928     ShapeEventListenerMap::iterator aIter;
1929     if( (aIter = maShapeEventListeners.find( xShape )) !=
1930         maShapeEventListeners.end() )
1931     {
1932         // entry for this shape found -> remove listener from
1933         // helper object
1934         ENSURE_OR_THROW(
1935             aIter->second.get(),
1936             "SlideShowImpl::removeShapeEventListener(): "
1937             "listener map contains NULL broadcast helper" );
1938 
1939         aIter->second->removeInterface( xListener );
1940     }
1941 
1942     maEventMultiplexer.notifyShapeListenerRemoved(xListener,
1943                                                   xShape);
1944 }
1945 
setShapeCursor(uno::Reference<drawing::XShape> const & xShape,sal_Int16 nPointerShape)1946 void SlideShowImpl::setShapeCursor(
1947     uno::Reference<drawing::XShape> const& xShape, sal_Int16 nPointerShape )
1948     throw (uno::RuntimeException)
1949 {
1950     osl::MutexGuard const guard( m_aMutex );
1951 
1952     if (isDisposed())
1953         return;
1954 
1955     // precondition: must only be called from the main thread!
1956     DBG_TESTSOLARMUTEX();
1957 
1958     ShapeCursorMap::iterator aIter;
1959     if( (aIter=maShapeCursors.find( xShape )) == maShapeCursors.end() )
1960     {
1961         // no entry for this shape -> create one
1962         if( nPointerShape != awt::SystemPointer::ARROW )
1963         {
1964             // add new entry, unless shape shall display
1965             // normal pointer arrow -> no need to handle that
1966             // case
1967             maShapeCursors.insert(
1968                 ShapeCursorMap::value_type(xShape,
1969                                            nPointerShape) );
1970         }
1971     }
1972     else if( nPointerShape == awt::SystemPointer::ARROW )
1973     {
1974         // shape shall display normal cursor -> can disable
1975         // the cursor and clear the entry
1976         maShapeCursors.erase( xShape );
1977     }
1978     else
1979     {
1980         // existing entry found, update with new cursor ID
1981         aIter->second = nPointerShape;
1982     }
1983 
1984     maEventMultiplexer.notifyShapeCursorChange(xShape,
1985                                                nPointerShape);
1986 }
1987 
requestCursor(sal_Int16 nCursorShape)1988 bool SlideShowImpl::requestCursor( sal_Int16 nCursorShape )
1989 {
1990     mnCurrentCursor = nCursorShape;
1991 
1992     const sal_Int16 nActualCursor = calcActiveCursor(mnCurrentCursor);
1993 
1994     // change all views to the requested cursor ID
1995     std::for_each( maViewContainer.begin(),
1996                    maViewContainer.end(),
1997                    boost::bind( &View::setCursorShape,
1998                                 _1,
1999                                 nActualCursor ));
2000 
2001     return nActualCursor==nCursorShape;
2002 }
2003 
resetCursor()2004 void SlideShowImpl::resetCursor()
2005 {
2006     mnCurrentCursor = awt::SystemPointer::ARROW;
2007 
2008     // change all views to the default cursor ID
2009     std::for_each( maViewContainer.begin(),
2010                    maViewContainer.end(),
2011                    boost::bind( &View::setCursorShape,
2012                                 _1,
2013                                 calcActiveCursor(mnCurrentCursor) ));
2014 }
2015 
update(double & nNextTimeout)2016 sal_Bool SlideShowImpl::update( double & nNextTimeout )
2017     throw (uno::RuntimeException)
2018 {
2019     osl::MutexGuard const guard( m_aMutex );
2020 
2021     if (isDisposed())
2022         return false;
2023 
2024     // precondition: update() must only be called from the
2025     // main thread!
2026     DBG_TESTSOLARMUTEX();
2027 
2028     if( mbShowPaused )
2029     {
2030         // commit frame (might be repaints pending)
2031         maScreenUpdater.commitUpdates();
2032 
2033         return false;
2034     }
2035     else
2036     {
2037         // TODO(F2): re-evaluate whether that timer lagging makes
2038         // sense.
2039 
2040         // hold timer, while processing the queues:
2041         // 1. when there is more than one active activity this ensures the
2042         //    same time for all activities and events
2043         // 2. processing of events may lead to creation of further events
2044         //    that have zero delay. While the timer is stopped these events
2045         //    are processed in the same run.
2046         {
2047             comphelper::ScopeGuard scopeGuard(
2048                 boost::bind( &canvas::tools::ElapsedTime::releaseTimer,
2049                              boost::cref(mpPresTimer) ) );
2050             mpPresTimer->holdTimer();
2051 
2052             // process queues
2053             maEventQueue.process();
2054 
2055             // #118671# the call above may execute a macro bound to an object. In
2056             // that case this macro may have destroyed this local slideshow so that it
2057             // is disposed (see bugdoc at task). In that case, detect this and exit
2058             // gently from this slideshow. Do not forget to disable the scoped
2059             // call to mpPresTimer, this will be deleted if we are disposed.
2060             if (isDisposed())
2061             {
2062                 scopeGuard.dismiss();
2063                 return false;
2064             }
2065 
2066             maActivitiesQueue.process();
2067 
2068             // commit frame to screen
2069             maFrameSynchronization.Synchronize();
2070             maScreenUpdater.commitUpdates();
2071 
2072             // TODO(Q3): remove need to call dequeued() from
2073             // activities. feels like a wart.
2074             //
2075             // Rationale for ActivitiesQueue::processDequeued(): when
2076             // an activity ends, it usually pushed the end state to
2077             // the animated shape in question, and ends the animation
2078             // (which, in turn, will usually disable shape sprite
2079             // mode). Disabling shape sprite mode causes shape
2080             // repaint, which, depending on slide content, takes
2081             // considerably more time than sprite updates. Thus, the
2082             // last animation step tends to look delayed. To
2083             // camouflage this, reaching end position and disabling
2084             // sprite mode is split into two (normal Activity::end(),
2085             // and Activity::dequeued()). Now, the reason to call
2086             // commitUpdates() twice here is caused by the unrelated
2087             // fact that during wait cursor display/hide, the screen
2088             // is updated, and shows hidden sprites, but, in case of
2089             // leaving the second commitUpdates() call out and punting
2090             // that to the next round, no updated static slide
2091             // content. In short, the last shape animation of a slide
2092             // tends to blink at its end.
2093 
2094             // process dequeued activities _after_ commit to screen
2095             maActivitiesQueue.processDequeued();
2096 
2097             // commit frame to screen
2098             maScreenUpdater.commitUpdates();
2099         }
2100         // Time held until here
2101 
2102         const bool bActivitiesLeft = (! maActivitiesQueue.isEmpty());
2103         const bool bTimerEventsLeft = (! maEventQueue.isEmpty());
2104         const bool bRet = (bActivitiesLeft || bTimerEventsLeft);
2105 
2106         if (bRet)
2107         {
2108             // calc nNextTimeout value:
2109             if (bActivitiesLeft)
2110             {
2111                 // Activity queue is not empty. Tell caller that we would
2112                 // like to render another frame.
2113 
2114                 // Return a zero time-out to signal our caller to call us
2115                 // back as soon as possible. The actual timing, waiting the
2116                 // appropriate amount of time between frames, is then done
2117                 // by the maFrameSynchronization object.
2118                 nNextTimeout = 0;
2119                 maFrameSynchronization.Activate();
2120             }
2121             else
2122             {
2123                 // timer events left:
2124                 // difference from current time (nota bene:
2125                 // time no longer held here!) to the next event in
2126                 // the event queue.
2127 
2128                 // #i61190# Retrieve next timeout only _after_
2129                 // processing activity queue
2130 
2131                 // ensure positive value:
2132                 nNextTimeout = std::max( 0.0, maEventQueue.nextTimeout() );
2133 
2134                 // There is no active animation so the frame rate does not
2135                 // need to be synchronized.
2136                 maFrameSynchronization.Deactivate();
2137             }
2138 
2139             mbSlideShowIdle = false;
2140         }
2141 
2142 #if defined(VERBOSE) && defined(DBG_UTIL)
2143         // when slideshow is idle, issue an XUpdatable::update() call
2144         // exactly once after a previous animation sequence finished -
2145         // this might trigger screen dumps on some canvas
2146         // implementations
2147         if( !mbSlideShowIdle &&
2148             (!bRet ||
2149              nNextTimeout > 1.0) )
2150         {
2151             UnoViewVector::const_iterator       aCurr(maViewContainer.begin());
2152             const UnoViewVector::const_iterator aEnd(maViewContainer.end());
2153             while( aCurr != aEnd )
2154             {
2155                 try
2156                 {
2157                     uno::Reference< presentation::XSlideShowView > xView( (*aCurr)->getUnoView(),
2158                                                                           uno::UNO_QUERY_THROW );
2159                     uno::Reference< util::XUpdatable >             xUpdatable( xView->getCanvas(),
2160                                                                                uno::UNO_QUERY_THROW );
2161                     xUpdatable->update();
2162                 }
2163                 catch( uno::RuntimeException& )
2164                 {
2165                     throw;
2166                 }
2167                 catch( uno::Exception& )
2168                 {
2169                     OSL_ENSURE( false,
2170                                 rtl::OUStringToOString(
2171                                     comphelper::anyToString( cppu::getCaughtException() ),
2172                                     RTL_TEXTENCODING_UTF8 ).getStr() );
2173                 }
2174 
2175                 ++aCurr;
2176             }
2177 
2178             mbSlideShowIdle = true;
2179         }
2180 #endif
2181 
2182         return bRet;
2183     }
2184 }
2185 
notifySlideTransitionEnded(bool bPaintSlide)2186 void SlideShowImpl::notifySlideTransitionEnded( bool bPaintSlide )
2187 {
2188     osl::MutexGuard const guard( m_aMutex );
2189 
2190     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2191     OSL_ENSURE( mpCurrentSlide,
2192                 "notifySlideTransitionEnded(): Invalid current slide" );
2193     if (mpCurrentSlide)
2194     {
2195 		mpCurrentSlide->update_settings( !!maUserPaintColor, maUserPaintColor ? *maUserPaintColor : RGBColor(), maUserPaintStrokeWidth );
2196 
2197 		// first init show, to give the animations
2198         // the chance to register SlideStartEvents
2199         const bool bBackgroundLayerRendered( !bPaintSlide );
2200         mpCurrentSlide->show( bBackgroundLayerRendered );
2201         maEventMultiplexer.notifySlideStartEvent();
2202     }
2203 }
2204 
queryAutomaticSlideTransition(uno::Reference<drawing::XDrawPage> const & xDrawPage,double & nAutomaticNextSlideTimeout,bool & bHasAutomaticNextSlide)2205 void queryAutomaticSlideTransition( uno::Reference<drawing::XDrawPage> const& xDrawPage,
2206                                     double&                                   nAutomaticNextSlideTimeout,
2207                                     bool&                                     bHasAutomaticNextSlide )
2208 {
2209     // retrieve slide change parameters from XDrawPage
2210     // ===============================================
2211 
2212     uno::Reference< beans::XPropertySet > xPropSet( xDrawPage,
2213                                                     uno::UNO_QUERY );
2214 
2215     sal_Int32 nChange(0);
2216     if( !xPropSet.is() ||
2217         !getPropertyValue( nChange,
2218                            xPropSet,
2219                            ::rtl::OUString(
2220                                RTL_CONSTASCII_USTRINGPARAM("Change"))) )
2221     {
2222         OSL_TRACE(
2223             "queryAutomaticSlideTransition(): "
2224             "Could not extract slide change mode from XDrawPage - assuming <none>\n" );
2225     }
2226 
2227     bHasAutomaticNextSlide = nChange == 1;
2228 
2229     if( !xPropSet.is() ||
2230         !getPropertyValue( nAutomaticNextSlideTimeout,
2231                            xPropSet,
2232                            ::rtl::OUString(
2233                                RTL_CONSTASCII_USTRINGPARAM("Duration"))) )
2234     {
2235         OSL_TRACE(
2236             "queryAutomaticSlideTransition(): "
2237             "Could not extract slide transition timeout from "
2238             "XDrawPage - assuming 1 sec\n" );
2239     }
2240 }
2241 
notifySlideAnimationsEnded()2242 void SlideShowImpl::notifySlideAnimationsEnded()
2243 {
2244     osl::MutexGuard const guard( m_aMutex );
2245 
2246     // Draw polygons above animations
2247     mpCurrentSlide->drawPolygons();
2248 
2249     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2250 
2251     // This struct will receive the (interruptible) event,
2252     // that triggers the notifySlideEnded() method.
2253     InterruptableEventPair aNotificationEvents;
2254 
2255     if( maEventMultiplexer.getAutomaticMode() )
2256     {
2257         OSL_ENSURE( ! mpRehearseTimingsActivity,
2258                     "unexpected: RehearseTimings mode!" );
2259 
2260         // schedule a slide end event, with automatic mode's
2261         // delay
2262         aNotificationEvents = makeInterruptableDelay(
2263             boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2264             maEventMultiplexer.getAutomaticTimeout() );
2265     }
2266     else
2267     {
2268         OSL_ENSURE( mpCurrentSlide,
2269                     "notifySlideAnimationsEnded(): Invalid current slide!" );
2270 
2271         bool   bHasAutomaticNextSlide=false;
2272         double nAutomaticNextSlideTimeout=0.0;
2273         queryAutomaticSlideTransition(mpCurrentSlide->getXDrawPage(),
2274                                       nAutomaticNextSlideTimeout,
2275                                       bHasAutomaticNextSlide);
2276 
2277         // check whether slide transition should happen
2278         // 'automatically'. If yes, simply schedule the
2279         // specified timeout.
2280         // NOTE: mbForceManualAdvance and mpRehearseTimingsActivity
2281         // override any individual slide setting, to always
2282         // step slides manually.
2283         if( !mbForceManualAdvance &&
2284             !mpRehearseTimingsActivity &&
2285             bHasAutomaticNextSlide )
2286         {
2287             aNotificationEvents = makeInterruptableDelay(
2288                 boost::bind<void>( boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2289                 nAutomaticNextSlideTimeout);
2290 
2291             // TODO(F2): Provide a mechanism to let the user override
2292             // this automatic timeout via next()
2293         }
2294         else
2295         {
2296             if (mpRehearseTimingsActivity)
2297                 mpRehearseTimingsActivity->start();
2298 
2299             // generate click event. Thus, the user must
2300             // trigger the actual end of a slide. No need to
2301             // generate interruptible event here, there's no
2302             // timeout involved.
2303             aNotificationEvents.mpImmediateEvent =
2304                 makeEvent( boost::bind<void>(
2305                     boost::mem_fn(&SlideShowImpl::notifySlideEnded), this, false ),
2306                     "SlideShowImpl::notifySlideEnded");
2307         }
2308     }
2309 
2310     // register events on the queues. To make automatic slide
2311     // changes interruptible, register the interruption event
2312     // as a nextEffectEvent target. Note that the timeout
2313     // event is optional (e.g. manual slide changes don't
2314     // generate a timeout)
2315     maUserEventQueue.registerNextEffectEvent(
2316         aNotificationEvents.mpImmediateEvent );
2317 
2318     if( aNotificationEvents.mpTimeoutEvent )
2319         maEventQueue.addEvent( aNotificationEvents.mpTimeoutEvent );
2320 
2321     // current slide's main sequence is over. Now should be
2322     // the time to prefetch the next slide (if any), and
2323     // prepare the initial slide bitmap (speeds up slide
2324     // change setup time a lot). Show the wait cursor, this
2325     // indeed might take some seconds.
2326     {
2327         WaitSymbolLock aLock (*this);
2328 
2329         if (! matches( mpPrefetchSlide,
2330                        mxPrefetchSlide, mxPrefetchAnimationNode ))
2331         {
2332             mpPrefetchSlide = makeSlide( mxPrefetchSlide, mxDrawPagesSupplier,
2333                                          mxPrefetchAnimationNode );
2334         }
2335         if (mpPrefetchSlide)
2336         {
2337             // ignore return value, this is just to populate
2338             // Slide's internal bitmap buffer, such that the time
2339             // needed to generate the slide bitmap is not spent
2340             // when the slide change is requested.
2341             mpPrefetchSlide->getCurrentSlideBitmap( *maViewContainer.begin() );
2342         }
2343     } // finally
2344 
2345     maListenerContainer.forEach<presentation::XSlideShowListener>(
2346         boost::mem_fn( &presentation::XSlideShowListener::slideAnimationsEnded ) );
2347 }
2348 
notifySlideEnded(const bool bReverse)2349 void SlideShowImpl::notifySlideEnded (const bool bReverse)
2350 {
2351     osl::MutexGuard const guard( m_aMutex );
2352 
2353     OSL_ENSURE( !isDisposed(), "### already disposed!" );
2354 
2355     if (mpRehearseTimingsActivity && !bReverse)
2356     {
2357         const double time = mpRehearseTimingsActivity->stop();
2358         if (mpRehearseTimingsActivity->hasBeenClicked())
2359         {
2360             // save time at current drawpage:
2361             uno::Reference<beans::XPropertySet> xPropSet(
2362                 mpCurrentSlide->getXDrawPage(), uno::UNO_QUERY );
2363             OSL_ASSERT( xPropSet.is() );
2364             if (xPropSet.is())
2365             {
2366                 xPropSet->setPropertyValue(
2367                     OUSTR("Change"),
2368                     uno::Any( static_cast<sal_Int32>(1) ) );
2369                 xPropSet->setPropertyValue(
2370                     OUSTR("Duration"),
2371                     uno::Any( static_cast<sal_Int32>(time) ) );
2372             }
2373         }
2374     }
2375 
2376     if (bReverse)
2377         maEventMultiplexer.notifySlideEndEvent();
2378 
2379     stopShow();  // MUST call that: results in
2380                  // maUserEventQueue.clear(). What's more,
2381                  // stopShow()'s currSlide->hide() call is
2382                  // now also required, notifySlideEnded()
2383                  // relies on that
2384                  // unconditionally. Otherwise, genuine
2385                  // shape animations (drawing layer and
2386                  // GIF) will not be stopped.
2387 
2388     maListenerContainer.forEach<presentation::XSlideShowListener>(
2389         boost::bind<void>(
2390             ::boost::mem_fn(&presentation::XSlideShowListener::slideEnded),
2391             _1,
2392             sal_Bool(bReverse)));
2393 }
2394 
notifyHyperLinkClicked(rtl::OUString const & hyperLink)2395 bool SlideShowImpl::notifyHyperLinkClicked( rtl::OUString const& hyperLink )
2396 {
2397     osl::MutexGuard const guard( m_aMutex );
2398 
2399     maListenerContainer.forEach<presentation::XSlideShowListener>(
2400         boost::bind( &presentation::XSlideShowListener::hyperLinkClicked,
2401                      _1,
2402                      boost::cref(hyperLink) ));
2403     return true;
2404 }
2405 
2406 /** Notification from eventmultiplexer that an animation event has occurred.
2407 	This will be forwarded to all registered XSlideShowListener
2408  */
handleAnimationEvent(const AnimationNodeSharedPtr & rNode)2409 bool SlideShowImpl::handleAnimationEvent( const AnimationNodeSharedPtr& rNode )
2410 {
2411     osl::MutexGuard const guard( m_aMutex );
2412 
2413 	uno::Reference<animations::XAnimationNode> xNode( rNode->getXAnimationNode() );
2414 
2415 	switch( rNode->getState() )
2416 	{
2417 	case AnimationNode::ACTIVE:
2418 	    maListenerContainer.forEach<presentation::XSlideShowListener>(
2419 		    boost::bind( &animations::XAnimationListener::beginEvent,
2420 			             _1,
2421 				         boost::cref(xNode) ));
2422 		break;
2423 
2424 	case AnimationNode::FROZEN:
2425 	case AnimationNode::ENDED:
2426 	    maListenerContainer.forEach<presentation::XSlideShowListener>(
2427 		    boost::bind( &animations::XAnimationListener::endEvent,
2428 			             _1,
2429 				         boost::cref(xNode) ));
2430         if(mpCurrentSlide->isPaintOverlayActive())
2431            mpCurrentSlide->drawPolygons();
2432 		break;
2433 	default:
2434 		break;
2435 	}
2436 
2437 	return true;
2438 }
2439 
2440 
2441 // ===== FrameSynchronization ==================================================
2442 
FrameSynchronization(const double nFrameDuration)2443 FrameSynchronization::FrameSynchronization (const double nFrameDuration)
2444     : maTimer(),
2445       mnFrameDuration(nFrameDuration),
2446       mnNextFrameTargetTime(0),
2447       mbIsActive(false)
2448 {
2449     MarkCurrentFrame();
2450 }
2451 
2452 
2453 
2454 
MarkCurrentFrame(void)2455 void FrameSynchronization::MarkCurrentFrame (void)
2456 {
2457     mnNextFrameTargetTime = maTimer.getElapsedTime() + mnFrameDuration;
2458 }
2459 
2460 
2461 
2462 
Synchronize(void)2463 void FrameSynchronization::Synchronize (void)
2464 {
2465     if (mbIsActive)
2466     {
2467         // Do busy waiting for now.
2468         while (maTimer.getElapsedTime() < mnNextFrameTargetTime)
2469             ;
2470     }
2471 
2472     MarkCurrentFrame();
2473 }
2474 
2475 
2476 
2477 
Activate(void)2478 void FrameSynchronization::Activate (void)
2479 {
2480     mbIsActive = true;
2481 }
2482 
2483 
2484 
2485 
Deactivate(void)2486 void FrameSynchronization::Deactivate (void)
2487 {
2488     mbIsActive = false;
2489 }
2490 
2491 
2492 
2493 
GetCurrentTime(void) const2494 double FrameSynchronization::GetCurrentTime (void) const
2495 {
2496     return maTimer.getElapsedTime();
2497 }
2498 
2499 
2500 } // anon namespace
2501 
2502 namespace sdecl = comphelper::service_decl;
2503 #if defined (__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)
2504  sdecl::class_<SlideShowImpl> serviceImpl;
2505  const sdecl::ServiceDecl slideShowDecl(
2506      serviceImpl,
2507 #else
2508  const sdecl::ServiceDecl slideShowDecl(
2509      sdecl::class_<SlideShowImpl>(),
2510 #endif
2511     "com.sun.star.comp.presentation.SlideShow",
2512     "com.sun.star.presentation.SlideShow" );
2513 
2514 // The C shared lib entry points
2515 COMPHELPER_SERVICEDECL_EXPORTS1(slideShowDecl)
2516 
2517