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