1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_slideshow.hxx"
30 
31 #include <canvas/debug.hxx>
32 #include <tools/diagnose_ex.h>
33 
34 #include <basegfx/matrix/b2dhommatrix.hxx>
35 #include <basegfx/tools/canvastools.hxx>
36 #include <basegfx/polygon/b2dpolygontools.hxx>
37 #include <basegfx/polygon/b2dpolypolygontools.hxx>
38 
39 #include <cppcanvas/basegfxfactory.hxx>
40 
41 #include <comphelper/optional.hxx>
42 #include <comphelper/make_shared_from_uno.hxx>
43 
44 #include <com/sun/star/rendering/XIntegerBitmap.hpp>
45 #include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
46 #include <com/sun/star/animations/TransitionType.hpp>
47 #include <com/sun/star/animations/TransitionSubType.hpp>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 
50 #include "slidechangebase.hxx"
51 #include "transitionfactory.hxx"
52 #include "transitiontools.hxx"
53 #include "parametricpolypolygonfactory.hxx"
54 #include "animationfactory.hxx"
55 #include "clippingfunctor.hxx"
56 #include "combtransition.hxx"
57 #include "tools.hxx"
58 
59 #include <boost/bind.hpp>
60 
61 
62 /***************************************************
63  ***                                             ***
64  ***          Slide Transition Effects           ***
65  ***                                             ***
66  ***************************************************/
67 
68 using namespace com::sun::star;
69 
70 namespace slideshow {
71 namespace internal {
72 
73 namespace {
74 
75 // helper methods
76 // =============================================
77 
78 void fillPage( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
79                const ::basegfx::B2DSize&           rPageSizePixel,
80                const RGBColor&                     rFillColor )
81 {
82     // need to render without any transformation (we
83     // assume rPageSizePixel to represent device units)
84     const ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
85         rDestinationCanvas->clone() );
86     pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
87 
88     // TODO(F2): Properly respect clip here.
89     // Might have to be transformed, too.
90     const ::basegfx::B2DHomMatrix aViewTransform(
91         rDestinationCanvas->getTransformation() );
92     const ::basegfx::B2DPoint aOutputPosPixel(
93         aViewTransform * ::basegfx::B2DPoint() );
94 
95     fillRect( pDevicePixelCanvas,
96               ::basegfx::B2DRectangle(
97                   aOutputPosPixel.getX(),
98                   aOutputPosPixel.getY(),
99                   aOutputPosPixel.getX() + rPageSizePixel.getX(),
100                   aOutputPosPixel.getY() + rPageSizePixel.getY() ),
101               rFillColor.getIntegerColor() );
102 }
103 
104 class PluginSlideChange: public SlideChangeBase
105 {
106     struct TransitionViewPair {
107 	uno::Reference<presentation::XTransition> mxTransition;
108 	UnoViewSharedPtr mpView;
109 
110 	TransitionViewPair( uno::Reference<presentation::XTransition> xTransition, const UnoViewSharedPtr pView )
111 	{
112 	    mxTransition = xTransition;
113 	    mpView = pView;
114 	}
115 
116 	~TransitionViewPair()
117 	{
118 	    mxTransition.clear();
119 	    mpView.reset();;
120 	}
121 
122 	void update( double t )
123 	{
124 	    mxTransition->update( t );
125 	}
126     };
127 
128 public:
129     /** Create a new SlideChanger, for the given leaving and
130         entering slide bitmaps, which uses super secret OpenGL
131         stuff.
132     */
133     PluginSlideChange( sal_Int16                                nTransitionType,
134                        sal_Int16                                nTransitionSubType,
135                        boost::optional<SlideSharedPtr> const&   leavingSlide_,
136                        const SlideSharedPtr&                    pEnteringSlide,
137                        const UnoViewContainer&                  rViewContainer,
138                        ScreenUpdater&                           rScreenUpdater,
139                        const uno::Reference<
140                              presentation::XTransitionFactory>& xFactory,
141                        const SoundPlayerSharedPtr&              pSoundPlayer,
142                        EventMultiplexer&                        rEventMultiplexer) :
143         SlideChangeBase( leavingSlide_,
144                          pEnteringSlide,
145                          pSoundPlayer,
146                          rViewContainer,
147                          rScreenUpdater,
148                          rEventMultiplexer ),
149         maTransitions(),
150         mbSuccess( false ),
151 	mnTransitionType( nTransitionType ),
152 	mnTransitionSubType( nTransitionSubType ),
153 	mxFactory( xFactory )
154     {
155         // create one transition per view
156         UnoViewVector::const_iterator aCurrView (rViewContainer.begin());
157         const UnoViewVector::const_iterator aEnd(rViewContainer.end());
158         while( aCurrView != aEnd )
159         {
160 	    if(! addTransition( *aCurrView ) )
161 		return;
162 
163             ENSURE_OR_THROW(maTransitions.back() && maTransitions.back()->mxTransition.is(),
164                             "Failed to create plugin transition");
165             ++aCurrView;
166         }
167 	mbSuccess = true;
168     }
169 
170     ~PluginSlideChange()
171     {
172 	mxFactory.clear();
173 
174         ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
175         ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
176         while( aCurrView != aEnd )
177         {
178 	    delete (*aCurrView);
179             ++aCurrView;
180 	}
181 	maTransitions.clear();
182     }
183 
184     bool addTransition( const UnoViewSharedPtr& rView )
185     {
186 	uno::Reference<presentation::XTransition> rTransition = mxFactory->createTransition(
187 	    mnTransitionType,
188 	    mnTransitionSubType,
189 	    rView->getUnoView(),
190 	    getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
191 	    getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
192 
193 	if( rTransition.is() )
194 	    maTransitions.push_back( new TransitionViewPair( rTransition, rView ) );
195 	else
196 	    return false;
197 
198 	return true;
199     }
200 
201     virtual bool operator()( double t )
202     {
203         std::for_each(maTransitions.begin(),
204                       maTransitions.end(),
205                       boost::bind( &TransitionViewPair::update,
206                                    _1, t) );
207         return true;
208     }
209 
210     bool Success()
211     {
212         return mbSuccess;
213     }
214 
215     // ViewEventHandler
216     virtual void viewAdded( const UnoViewSharedPtr& rView )
217     {
218 	OSL_TRACE("PluginSlideChange viewAdded");
219 	SlideChangeBase::viewAdded( rView );
220 
221         ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
222         ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
223 	bool bKnown = false;
224         while( aCurrView != aEnd )
225         {
226 	    if( (*aCurrView)->mpView == rView ) {
227 		bKnown = true;
228 		break;
229 	    }
230             ++aCurrView;
231 	}
232 
233 	if( !bKnown ) {
234 	    OSL_TRACE("need to be added");
235 
236 	    addTransition( rView );
237 	}
238     }
239 
240     virtual void viewRemoved( const UnoViewSharedPtr& rView )
241     {
242 	OSL_TRACE("PluginSlideChange viewRemoved");
243 	SlideChangeBase::viewRemoved( rView );
244 
245         ::std::vector< TransitionViewPair* >::iterator aCurrView (maTransitions.begin());
246         ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
247         while( aCurrView != aEnd )
248         {
249 	    if( (*aCurrView)->mpView == rView ) {
250 		OSL_TRACE( "view removed" );
251 		delete (*aCurrView);
252 		maTransitions.erase( aCurrView );
253 		break;
254 	    }
255             ++aCurrView;
256 	}
257     }
258 
259     virtual void viewChanged( const UnoViewSharedPtr& rView )
260     {
261 	OSL_TRACE("PluginSlideChange viewChanged");
262 	SlideChangeBase::viewChanged( rView );
263 
264         ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
265         ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
266         while( aCurrView != aEnd )
267         {
268 	    if( (*aCurrView)->mpView == rView ) {
269 		OSL_TRACE( "view changed" );
270  		(*aCurrView)->mxTransition->viewChanged( rView->getUnoView(),
271 							 getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
272 							 getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
273 	    } else
274 		OSL_TRACE( "view did not changed" );
275 
276             ++aCurrView;
277 	}
278     }
279 
280     virtual void viewsChanged()
281     {
282 	OSL_TRACE("PluginSlideChange viewsChanged");
283 	SlideChangeBase::viewsChanged();
284 
285         ::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
286         ::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
287         while( aCurrView != aEnd )
288         {
289 	    OSL_TRACE( "view changed" );
290 	    (*aCurrView)->mxTransition->viewChanged( (*aCurrView)->mpView->getUnoView(),
291 						     getLeavingBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap(),
292 						     getEnteringBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap() );
293             ++aCurrView;
294 	}
295     }
296 
297 private:
298     // One transition object per view
299     std::vector< TransitionViewPair* > maTransitions;
300 
301     // bool
302     bool mbSuccess;
303 
304     sal_Int16 mnTransitionType;
305     sal_Int16 mnTransitionSubType;
306 
307     uno::Reference<presentation::XTransitionFactory> mxFactory;
308 };
309 
310 class ClippedSlideChange : public SlideChangeBase
311 {
312 public:
313     /** Create a new SlideChanger, for the given leaving and
314         entering slide bitmaps, which applies the given clip
315         polygon.
316     */
317     ClippedSlideChange(
318         const SlideSharedPtr&                   pEnteringSlide,
319         const ParametricPolyPolygonSharedPtr&   rPolygon,
320         const TransitionInfo&                   rTransitionInfo,
321         const UnoViewContainer&                 rViewContainer,
322         ScreenUpdater&                          rScreenUpdater,
323         EventMultiplexer&                       rEventMultiplexer,
324         bool                                    bDirectionForward,
325         const SoundPlayerSharedPtr&             pSoundPlayer ) :
326         SlideChangeBase(
327             // leaving bitmap is empty, we're leveraging the fact that the
328             // old slide is still displayed in the background:
329             boost::optional<SlideSharedPtr>(),
330             pEnteringSlide,
331             pSoundPlayer,
332             rViewContainer,
333             rScreenUpdater,
334             rEventMultiplexer ),
335         maClippingFunctor( rPolygon,
336                            rTransitionInfo,
337                            bDirectionForward,
338                            true )
339         {}
340 
341     virtual void performIn(
342         const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
343         const ViewEntry&                            rViewEntry,
344         const ::cppcanvas::CanvasSharedPtr&         rDestinationCanvas,
345         double                                      t );
346 
347     virtual void performOut(
348         const ::cppcanvas::CustomSpriteSharedPtr&  rSprite,
349         const ViewEntry&                           rViewEntry,
350         const ::cppcanvas::CanvasSharedPtr&        rDestinationCanvas,
351         double                                     t );
352 
353 private:
354     ClippingFunctor             maClippingFunctor;
355 };
356 
357 void ClippedSlideChange::performIn(
358     const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
359     const ViewEntry&                            rViewEntry,
360     const ::cppcanvas::CanvasSharedPtr&         /*rDestinationCanvas*/,
361     double                                      t )
362 {
363     // #i46602# Better work in device coordinate space here,
364     // otherwise, we too easily suffer from roundoffs. Apart from
365     // that, getEnteringSizePixel() _guarantees_ to cover the whole
366     // slide bitmap. There's a catch, though: this removes any effect
367     // of the view transformation (e.g. rotation) from the transition.
368     rSprite->setClipPixel(
369         maClippingFunctor( t,
370                            getEnteringSlideSizePixel(rViewEntry.mpView) ) );
371 }
372 
373 void ClippedSlideChange::performOut(
374     const ::cppcanvas::CustomSpriteSharedPtr&  /*rSprite*/,
375     const ViewEntry&                           /*rViewEntry*/,
376     const ::cppcanvas::CanvasSharedPtr&        /*rDestinationCanvas*/,
377     double                                     /*t*/ )
378 {
379     // not needed here
380 }
381 
382 
383 class FadingSlideChange : public SlideChangeBase
384 {
385 public:
386     /** Create a new SlideChanger, for the given leaving and
387         entering slides, which applies a fade effect.
388     */
389     FadingSlideChange(
390         boost::optional<SlideSharedPtr> const & leavingSlide,
391         const SlideSharedPtr&                   pEnteringSlide,
392         boost::optional<RGBColor> const&        rFadeColor,
393         const SoundPlayerSharedPtr&             pSoundPlayer,
394         const UnoViewContainer&                 rViewContainer,
395         ScreenUpdater&                          rScreenUpdater,
396         EventMultiplexer&                       rEventMultiplexer )
397         : SlideChangeBase( leavingSlide,
398                            pEnteringSlide,
399                            pSoundPlayer,
400                            rViewContainer,
401                            rScreenUpdater,
402                            rEventMultiplexer ),
403           maFadeColor( rFadeColor ),
404           mbFirstTurn( true )
405         {}
406 
407     virtual void performIn(
408         const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
409         const ViewEntry&                            rViewEntry,
410         const ::cppcanvas::CanvasSharedPtr&         rDestinationCanvas,
411         double                                      t );
412 
413     virtual void performOut(
414         const ::cppcanvas::CustomSpriteSharedPtr&  rSprite,
415         const ViewEntry&                           rViewEntry,
416         const ::cppcanvas::CanvasSharedPtr&        rDestinationCanvas,
417         double                                     t );
418 
419 private:
420     const boost::optional< RGBColor >               maFadeColor;
421     bool                                            mbFirstTurn;
422 };
423 
424 void FadingSlideChange::performIn(
425     const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
426     const ViewEntry&                            /*rViewEntry*/,
427     const ::cppcanvas::CanvasSharedPtr&         /*rDestinationCanvas*/,
428     double                                      t )
429 {
430     ENSURE_OR_THROW(
431         rSprite,
432         "FadingSlideChange::performIn(): Invalid sprite" );
433 
434     if( maFadeColor )
435         // After half of the active time, fade in new slide
436         rSprite->setAlpha( t > 0.5 ? 2.0*(t-0.5) : 0.0 );
437     else
438         // Fade in new slide over full active time
439         rSprite->setAlpha( t );
440 }
441 
442 void FadingSlideChange::performOut(
443     const ::cppcanvas::CustomSpriteSharedPtr&  rSprite,
444     const ViewEntry&                           rViewEntry,
445     const ::cppcanvas::CanvasSharedPtr&        rDestinationCanvas,
446     double                                     t )
447 {
448     ENSURE_OR_THROW(
449         rSprite,
450         "FadingSlideChange::performOut(): Invalid sprite" );
451     ENSURE_OR_THROW(
452         rDestinationCanvas,
453         "FadingSlideChange::performOut(): Invalid dest canvas" );
454 
455     // only needed for color fades
456     if( maFadeColor )
457     {
458         if( mbFirstTurn )
459         {
460             mbFirstTurn = false;
461 
462             // clear page to given fade color. 'Leaving' slide is
463             // painted atop of that, but slowly fading out.
464             fillPage( rDestinationCanvas,
465                       getEnteringSlideSizePixel( rViewEntry.mpView ),
466                       *maFadeColor );
467         }
468 
469         // Until half of the active time, fade out old
470         // slide. After half of the active time, old slide
471         // will be invisible.
472         rSprite->setAlpha( t > 0.5 ? 0.0 : 2.0*(0.5-t) );
473     }
474 }
475 
476 class MovingSlideChange : public SlideChangeBase
477 {
478     /// Direction vector for leaving slide,
479     const ::basegfx::B2DVector  maLeavingDirection;
480 
481     /// Direction vector for entering slide,
482     const ::basegfx::B2DVector  maEnteringDirection;
483 
484     bool                        mbFirstPerformCall;
485 
486 public:
487     /** Create a new SlideChanger, for the given entering slide
488         bitmaps, which performes a moving slide change effect
489 
490         @param rLeavingDirection
491         Direction vector. The move is performed along this
492         direction vector, starting at a position where the leaving
493         slide is fully visible, and ending at a position where the
494         leaving slide is just not visible. The vector must have
495         unit length.
496 
497         @param rEnteringDirection
498         Direction vector. The move is performed along this
499         direction vector, starting at a position where the
500         entering slide is just not visible, and ending at the
501         final slide position. The vector must have unit length.
502     */
503     MovingSlideChange(
504         const boost::optional<SlideSharedPtr>& leavingSlide,
505         const SlideSharedPtr&                  pEnteringSlide,
506         const SoundPlayerSharedPtr&            pSoundPlayer,
507         const UnoViewContainer&                rViewContainer,
508         ScreenUpdater&                         rScreenUpdater,
509         EventMultiplexer&                      rEventMultiplexer,
510         const ::basegfx::B2DVector&            rLeavingDirection,
511         const ::basegfx::B2DVector&            rEnteringDirection )
512         : SlideChangeBase(
513             leavingSlide, pEnteringSlide, pSoundPlayer,
514             rViewContainer, rScreenUpdater, rEventMultiplexer,
515             // Optimization: when leaving bitmap is given,
516             // but it does not move, don't create sprites for it,
517             // we simply paint it once at startup:
518             !rLeavingDirection.equalZero() /* bCreateLeavingSprites */,
519             !rEnteringDirection.equalZero() /* bCreateEnteringSprites */ ),
520           // TODO(F1): calc correct length of direction
521           // vector. Directions not strictly horizontal or vertical
522           // must travel a longer distance.
523           maLeavingDirection( rLeavingDirection ),
524           // TODO(F1): calc correct length of direction
525           // vector. Directions not strictly horizontal or vertical
526           // must travel a longer distance.
527           maEnteringDirection( rEnteringDirection ),
528           mbFirstPerformCall( true )
529         {}
530 
531     virtual void performIn(
532         const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
533         const ViewEntry&                            rViewEntry,
534         const ::cppcanvas::CanvasSharedPtr&         rDestinationCanvas,
535         double                                      t );
536 
537     virtual void performOut(
538         const ::cppcanvas::CustomSpriteSharedPtr&  rSprite,
539         const ViewEntry&                           rViewEntry,
540         const ::cppcanvas::CanvasSharedPtr&        rDestinationCanvas,
541         double                                     t );
542 };
543 
544 void MovingSlideChange::performIn(
545     const ::cppcanvas::CustomSpriteSharedPtr&   rSprite,
546     const ViewEntry&                            rViewEntry,
547     const ::cppcanvas::CanvasSharedPtr&         rDestinationCanvas,
548     double                                      t )
549 {
550     // intro sprite moves:
551 
552     ENSURE_OR_THROW(
553         rSprite,
554         "MovingSlideChange::performIn(): Invalid sprite" );
555     ENSURE_OR_THROW(
556         rDestinationCanvas,
557         "MovingSlideChange::performIn(): Invalid dest canvas" );
558 
559     if (mbFirstPerformCall && maLeavingDirection.equalZero())
560     {
561         mbFirstPerformCall = false;
562         renderBitmap( getLeavingBitmap(rViewEntry), rDestinationCanvas );
563     }
564 
565     // TODO(F1): This does not account for non-translational
566     // transformations! If the canvas is rotated, we still
567     // move the sprite unrotated (which might or might not
568     // produce the intended effect).
569     const basegfx::B2DHomMatrix aViewTransform(
570         rDestinationCanvas->getTransformation() );
571     const basegfx::B2DPoint aPageOrigin(
572         aViewTransform * basegfx::B2DPoint() );
573 
574     // move sprite
575     rSprite->movePixel(
576         aPageOrigin +
577         ((t - 1.0) *
578          ::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
579          maEnteringDirection) );
580 }
581 
582 void MovingSlideChange::performOut(
583     const ::cppcanvas::CustomSpriteSharedPtr&  rSprite,
584     const ViewEntry&                           rViewEntry,
585     const ::cppcanvas::CanvasSharedPtr&        rDestinationCanvas,
586     double                                     t )
587 {
588     // outro sprite moves:
589 
590     ENSURE_OR_THROW(
591         rSprite,
592         "MovingSlideChange::performOut(): Invalid sprite" );
593     ENSURE_OR_THROW(
594         rDestinationCanvas,
595         "MovingSlideChange::performOut(): Invalid dest canvas" );
596 
597     if (mbFirstPerformCall && maEnteringDirection.equalZero())
598     {
599         mbFirstPerformCall = false;
600         renderBitmap( getEnteringBitmap(rViewEntry), rDestinationCanvas );
601     }
602 
603     // TODO(F1): This does not account for non-translational
604     // transformations! If the canvas is rotated, we still
605     // move the sprite unrotated (which might or might not
606     // produce the intended effect).
607     const basegfx::B2DHomMatrix aViewTransform(
608         rDestinationCanvas->getTransformation() );
609     const basegfx::B2DPoint aPageOrigin(
610         aViewTransform * basegfx::B2DPoint() );
611 
612     // move sprite
613     rSprite->movePixel(
614         aPageOrigin + (t *
615                        ::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
616                        maLeavingDirection) );
617 }
618 
619 
620 NumberAnimationSharedPtr createPushWipeTransition(
621     boost::optional<SlideSharedPtr> const &         leavingSlide_,
622     const SlideSharedPtr&                           pEnteringSlide,
623     const UnoViewContainer&                         rViewContainer,
624     ScreenUpdater&                                  rScreenUpdater,
625     EventMultiplexer&                               rEventMultiplexer,
626     sal_Int16                                       /*nTransitionType*/,
627     sal_Int16                                       nTransitionSubType,
628     bool                                            /*bTransitionDirection*/,
629     const SoundPlayerSharedPtr&                     pSoundPlayer )
630 {
631     boost::optional<SlideSharedPtr> leavingSlide; // no bitmap
632     if (leavingSlide_ && (*leavingSlide_).get() != 0)
633     {
634         // opt: only page, if we've an
635         // actual slide to move out here. We
636         // _don't_ need a fake black background
637         // bitmap, neither for push nor for comb
638         // wipes.
639         leavingSlide = leavingSlide_;
640     }
641 
642     // setup direction vector
643     bool bComb( false );
644     ::basegfx::B2DVector aDirection;
645     switch( nTransitionSubType )
646     {
647     default:
648         OSL_ENSURE(
649             false,
650             "createPushWipeTransition(): Unexpected transition "
651             "subtype for animations::TransitionType::PUSHWIPE "
652             "transitions" );
653         return NumberAnimationSharedPtr();
654 
655     case animations::TransitionSubType::FROMTOP:
656         aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
657         break;
658 
659     case animations::TransitionSubType::FROMBOTTOM:
660         aDirection = ::basegfx::B2DVector( 0.0, -1.0 );
661         break;
662 
663     case animations::TransitionSubType::FROMLEFT:
664         aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
665         break;
666 
667     case animations::TransitionSubType::FROMRIGHT:
668         aDirection = ::basegfx::B2DVector( -1.0, 0.0 );
669         break;
670 
671     case animations::TransitionSubType::FROMBOTTOMRIGHT:
672         aDirection = ::basegfx::B2DVector( -1.0, -1.0 );
673         break;
674 
675     case animations::TransitionSubType::FROMBOTTOMLEFT:
676         aDirection = ::basegfx::B2DVector( 1.0, -1.0 );
677         break;
678 
679     case animations::TransitionSubType::FROMTOPRIGHT:
680         aDirection = ::basegfx::B2DVector( -1.0, 1.0 );
681         break;
682 
683     case animations::TransitionSubType::FROMTOPLEFT:
684         aDirection = ::basegfx::B2DVector( 1.0, 1.0 );
685         break;
686 
687     case animations::TransitionSubType::COMBHORIZONTAL:
688         aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
689         bComb = true;
690         break;
691 
692     case animations::TransitionSubType::COMBVERTICAL:
693         aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
694         bComb = true;
695         break;
696     }
697 
698     if( bComb )
699     {
700         return NumberAnimationSharedPtr(
701             new CombTransition( leavingSlide,
702                                 pEnteringSlide,
703                                 pSoundPlayer,
704                                 rViewContainer,
705                                 rScreenUpdater,
706                                 rEventMultiplexer,
707                                 aDirection,
708                                 24 /* comb with 12 stripes */ ));
709     }
710     else
711     {
712         return NumberAnimationSharedPtr(
713             new MovingSlideChange( leavingSlide,
714                                    pEnteringSlide,
715                                    pSoundPlayer,
716                                    rViewContainer,
717                                    rScreenUpdater,
718                                    rEventMultiplexer,
719                                    aDirection,
720                                    aDirection ));
721     }
722 }
723 
724 NumberAnimationSharedPtr createSlideWipeTransition(
725     boost::optional<SlideSharedPtr> const &         leavingSlide,
726     const SlideSharedPtr&                           pEnteringSlide,
727     const UnoViewContainer&                         rViewContainer,
728     ScreenUpdater&                                  rScreenUpdater,
729     EventMultiplexer&                               rEventMultiplexer,
730     sal_Int16                                       /*nTransitionType*/,
731     sal_Int16                                       nTransitionSubType,
732     bool                                            bTransitionDirection,
733     const SoundPlayerSharedPtr&                     pSoundPlayer )
734 {
735     // setup 'in' direction vector
736     ::basegfx::B2DVector aInDirection;
737     switch( nTransitionSubType )
738     {
739     default:
740         OSL_ENSURE(
741             false,
742             "createSlideWipeTransition(): Unexpected transition "
743             "subtype for animations::TransitionType::SLIDEWIPE "
744             "transitions" );
745         return NumberAnimationSharedPtr();
746 
747     case animations::TransitionSubType::FROMTOP:
748         aInDirection = ::basegfx::B2DVector( 0.0, 1.0 );
749         break;
750 
751     case animations::TransitionSubType::FROMRIGHT:
752         aInDirection = ::basegfx::B2DVector( -1.0, 0.0 );
753         break;
754 
755     case animations::TransitionSubType::FROMLEFT:
756         aInDirection = ::basegfx::B2DVector( 1.0, 0.0 );
757         break;
758 
759     case animations::TransitionSubType::FROMBOTTOM:
760         aInDirection = ::basegfx::B2DVector( 0.0, -1.0 );
761         break;
762 
763     case animations::TransitionSubType::FROMBOTTOMRIGHT:
764         aInDirection = ::basegfx::B2DVector( -1.0, -1.0 );
765         break;
766 
767     case animations::TransitionSubType::FROMBOTTOMLEFT:
768         aInDirection = ::basegfx::B2DVector( 1.0, -1.0 );
769         break;
770 
771     case animations::TransitionSubType::FROMTOPRIGHT:
772         aInDirection = ::basegfx::B2DVector( -1.0, 1.0 );
773         break;
774 
775     case animations::TransitionSubType::FROMTOPLEFT:
776         aInDirection = ::basegfx::B2DVector( 1.0, 1.0 );
777         break;
778     }
779 
780     if( bTransitionDirection )
781     {
782         // normal, 'forward' slide wipe effect. Since the old
783         // content is still on screen (and does not move), we omit
784         // the 'leaving' slide.
785         // =======================================================
786 
787         return NumberAnimationSharedPtr(
788             new MovingSlideChange(
789                 boost::optional<SlideSharedPtr>() /* no slide */,
790                 pEnteringSlide,
791                 pSoundPlayer,
792                 rViewContainer,
793                 rScreenUpdater,
794                 rEventMultiplexer,
795                 basegfx::B2DVector(),
796                 aInDirection ));
797     }
798     else
799     {
800         // 'reversed' slide wipe effect. Reverse for slide wipes
801         // means, that the new slide is in the back, statically,
802         // and the old one is moving off in the foreground.
803         // =======================================================
804 
805         return NumberAnimationSharedPtr(
806             new MovingSlideChange( leavingSlide,
807                                    pEnteringSlide,
808                                    pSoundPlayer,
809                                    rViewContainer,
810                                    rScreenUpdater,
811                                    rEventMultiplexer,
812                                    aInDirection,
813                                    basegfx::B2DVector() ));
814     }
815 }
816 
817 NumberAnimationSharedPtr createPluginTransition(
818     sal_Int16                                nTransitionType,
819     sal_Int16                                nTransitionSubType,
820     boost::optional<SlideSharedPtr> const&   pLeavingSlide,
821     const SlideSharedPtr&                    pEnteringSlide,
822     const UnoViewContainer&                  rViewContainer,
823     ScreenUpdater&                           rScreenUpdater,
824     const uno::Reference<
825           presentation::XTransitionFactory>& xFactory,
826     const SoundPlayerSharedPtr&              pSoundPlayer,
827     EventMultiplexer&                        rEventMultiplexer)
828 {
829     PluginSlideChange* pTransition =
830         new PluginSlideChange(
831             nTransitionType,
832             nTransitionSubType,
833             pLeavingSlide,
834             pEnteringSlide,
835             rViewContainer,
836             rScreenUpdater,
837             xFactory,
838             pSoundPlayer,
839             rEventMultiplexer );
840 
841     if( pTransition->Success() )
842         return NumberAnimationSharedPtr( pTransition );
843     else {
844         delete pTransition;
845         return NumberAnimationSharedPtr();
846     }
847 }
848 
849 } // anon namespace
850 
851 
852 NumberAnimationSharedPtr TransitionFactory::createSlideTransition(
853     const SlideSharedPtr&                                   pLeavingSlide,
854     const SlideSharedPtr&                                   pEnteringSlide,
855     const UnoViewContainer&                                 rViewContainer,
856     ScreenUpdater&                                          rScreenUpdater,
857     EventMultiplexer&                                       rEventMultiplexer,
858     const uno::Reference<presentation::XTransitionFactory>& xOptionalFactory,
859     sal_Int16                                               nTransitionType,
860     sal_Int16                                               nTransitionSubType,
861     bool                                                    bTransitionDirection,
862     const RGBColor&                                         rTransitionFadeColor,
863     const SoundPlayerSharedPtr&                             pSoundPlayer            )
864 {
865     // xxx todo: change to TransitionType::NONE, TransitionSubType::NONE:
866     if (nTransitionType == 0 && nTransitionSubType == 0) {
867         // just play sound, no slide transition:
868         if (pSoundPlayer) {
869             pSoundPlayer->startPlayback();
870             // xxx todo: for now, presentation.cxx takes care about the slide
871             // #i50492#  transition sound object, so just release it here
872         }
873         return NumberAnimationSharedPtr();
874     }
875 
876     ENSURE_OR_THROW(
877         pEnteringSlide,
878         "TransitionFactory::createSlideTransition(): Invalid entering slide" );
879 
880     if( xOptionalFactory.is() &&
881         xOptionalFactory->hasTransition(nTransitionType, nTransitionSubType) )
882     {
883         // #i82460# - optional plugin factory claims this transition. delegate.
884         NumberAnimationSharedPtr pTransition(
885             createPluginTransition(
886                 nTransitionType,
887                 nTransitionSubType,
888                 comphelper::make_optional(pLeavingSlide),
889                 pEnteringSlide,
890                 rViewContainer,
891                 rScreenUpdater,
892                 xOptionalFactory,
893                 pSoundPlayer,
894                 rEventMultiplexer ));
895 
896         if( pTransition.get() )
897             return pTransition;
898     }
899 
900     const TransitionInfo* pTransitionInfo(
901         getTransitionInfo( nTransitionType, nTransitionSubType ) );
902 
903     if( pTransitionInfo != NULL )
904     {
905         switch( pTransitionInfo->meTransitionClass )
906         {
907             default:
908             case TransitionInfo::TRANSITION_INVALID:
909                 OSL_TRACE(
910                     "TransitionFactory::createSlideTransition(): "
911                     "Invalid type/subtype (%d/%d) combination encountered.",
912                     nTransitionType,
913                     nTransitionSubType );
914                 return NumberAnimationSharedPtr();
915 
916 
917             case TransitionInfo::TRANSITION_CLIP_POLYPOLYGON:
918             {
919                 // generate parametric poly-polygon
920                 ParametricPolyPolygonSharedPtr pPoly(
921                     ParametricPolyPolygonFactory::createClipPolyPolygon(
922                         nTransitionType, nTransitionSubType ) );
923 
924                 // create a clip transition from that
925                 return NumberAnimationSharedPtr(
926                     new ClippedSlideChange( pEnteringSlide,
927                                             pPoly,
928                                             *pTransitionInfo,
929                                             rViewContainer,
930                                             rScreenUpdater,
931                                             rEventMultiplexer,
932                                             bTransitionDirection,
933                                             pSoundPlayer ));
934             }
935 
936             case TransitionInfo::TRANSITION_SPECIAL:
937             {
938                 switch( nTransitionType )
939                 {
940                     default:
941                         OSL_ENSURE(
942                             false,
943                             "TransitionFactory::createSlideTransition(): "
944                             "Unexpected transition type for "
945                             "TRANSITION_SPECIAL transitions" );
946                         return NumberAnimationSharedPtr();
947 
948                     case animations::TransitionType::RANDOM:
949                     {
950                         // select randomly one of the effects from the
951                         // TransitionFactoryTable
952 
953                         const TransitionInfo* pRandomTransitionInfo(
954                             getRandomTransitionInfo() );
955 
956                         ENSURE_OR_THROW(
957                             pRandomTransitionInfo != NULL,
958                             "TransitionFactory::createSlideTransition(): "
959                             "Got invalid random transition info" );
960 
961                         ENSURE_OR_THROW(
962                             pRandomTransitionInfo->mnTransitionType !=
963                             animations::TransitionType::RANDOM,
964                             "TransitionFactory::createSlideTransition(): "
965                             "Got random again for random input!" );
966 
967                         // and recurse
968                         return createSlideTransition(
969                             pLeavingSlide,
970                             pEnteringSlide,
971                             rViewContainer,
972                             rScreenUpdater,
973                             rEventMultiplexer,
974                             xOptionalFactory,
975                             pRandomTransitionInfo->mnTransitionType,
976                             pRandomTransitionInfo->mnTransitionSubType,
977                             bTransitionDirection,
978                             rTransitionFadeColor,
979                             pSoundPlayer );
980                     }
981 
982                     case animations::TransitionType::PUSHWIPE:
983                     {
984                         return createPushWipeTransition(
985                             comphelper::make_optional(pLeavingSlide),
986                             pEnteringSlide,
987                             rViewContainer,
988                             rScreenUpdater,
989                             rEventMultiplexer,
990                             nTransitionType,
991                             nTransitionSubType,
992                             bTransitionDirection,
993                             pSoundPlayer );
994                     }
995 
996                     case animations::TransitionType::SLIDEWIPE:
997                     {
998                         return createSlideWipeTransition(
999                             comphelper::make_optional(pLeavingSlide),
1000                             pEnteringSlide,
1001                             rViewContainer,
1002                             rScreenUpdater,
1003                             rEventMultiplexer,
1004                             nTransitionType,
1005                             nTransitionSubType,
1006                             bTransitionDirection,
1007                             pSoundPlayer );
1008                     }
1009 
1010                     case animations::TransitionType::FADE:
1011                     {
1012                         // black page:
1013                         boost::optional<SlideSharedPtr> leavingSlide;
1014 
1015                         switch( nTransitionSubType )
1016                         {
1017                             case animations::TransitionSubType::CROSSFADE:
1018                                 // crossfade needs no further setup,
1019                                 // just blend new slide over existing
1020                                 // background.
1021                                 break;
1022 
1023                                 // TODO(F1): Implement toColor/fromColor fades
1024                             case animations::TransitionSubType::FADETOCOLOR:
1025                                 // FALLTHROUGH intended
1026                             case animations::TransitionSubType::FADEFROMCOLOR:
1027                                 // FALLTHROUGH intended
1028                             case animations::TransitionSubType::FADEOVERCOLOR:
1029                                 if (pLeavingSlide) {
1030                                     // only generate, if fade
1031                                     // effect really needs it.
1032                                     leavingSlide.reset( pLeavingSlide );
1033                                 }
1034                                 break;
1035 
1036                             default:
1037                                 ENSURE_OR_THROW( false,
1038                                                   "SlideTransitionFactory::createSlideTransition(): Unknown FADE subtype" );
1039                         }
1040 
1041                         return NumberAnimationSharedPtr(
1042                             new FadingSlideChange(
1043                                 leavingSlide,
1044                                 pEnteringSlide,
1045                                 comphelper::make_optional(
1046                                     rTransitionFadeColor),
1047                                 pSoundPlayer,
1048                                 rViewContainer,
1049                                 rScreenUpdater,
1050                                 rEventMultiplexer ));
1051                     }
1052                 }
1053             }
1054             break;
1055         }
1056     }
1057 
1058     // No animation generated, maybe no table entry for given
1059     // transition?
1060     OSL_TRACE(
1061         "TransitionFactory::createSlideTransition(): "
1062         "Unknown type/subtype (%d/%d) combination encountered",
1063         nTransitionType,
1064         nTransitionSubType );
1065     OSL_ENSURE(
1066         false,
1067         "TransitionFactory::createSlideTransition(): "
1068         "Unknown type/subtype combination encountered" );
1069 
1070     return NumberAnimationSharedPtr();
1071 }
1072 
1073 } // namespace internal
1074 } // namespace presentation
1075