blob: e34c515a05e430a3e1545c5a9fd06519619079c4 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_slideshow.hxx"
#include <canvas/debug.hxx>
#include <tools/diagnose_ex.h>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/tools/canvastools.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <cppcanvas/basegfxfactory.hxx>
#include <comphelper/optional.hxx>
#include <comphelper/make_shared_from_uno.hxx>
#include <com/sun/star/rendering/XIntegerBitmap.hpp>
#include <com/sun/star/rendering/IntegerBitmapLayout.hpp>
#include <com/sun/star/animations/TransitionType.hpp>
#include <com/sun/star/animations/TransitionSubType.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include "slidechangebase.hxx"
#include "transitionfactory.hxx"
#include "transitiontools.hxx"
#include "parametricpolypolygonfactory.hxx"
#include "animationfactory.hxx"
#include "clippingfunctor.hxx"
#include "combtransition.hxx"
#include "tools.hxx"
#include <boost/bind.hpp>
/***************************************************
*** ***
*** Slide Transition Effects ***
*** ***
***************************************************/
using namespace com::sun::star;
namespace slideshow {
namespace internal {
namespace {
// helper methods
// =============================================
void fillPage( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
const ::basegfx::B2DSize& rPageSizePixel,
const RGBColor& rFillColor )
{
// need to render without any transformation (we
// assume rPageSizePixel to represent device units)
const ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
rDestinationCanvas->clone() );
pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
// TODO(F2): Properly respect clip here.
// Might have to be transformed, too.
const ::basegfx::B2DHomMatrix aViewTransform(
rDestinationCanvas->getTransformation() );
const ::basegfx::B2DPoint aOutputPosPixel(
aViewTransform * ::basegfx::B2DPoint() );
fillRect( pDevicePixelCanvas,
::basegfx::B2DRectangle(
aOutputPosPixel.getX(),
aOutputPosPixel.getY(),
aOutputPosPixel.getX() + rPageSizePixel.getX(),
aOutputPosPixel.getY() + rPageSizePixel.getY() ),
rFillColor.getIntegerColor() );
}
class PluginSlideChange: public SlideChangeBase
{
struct TransitionViewPair {
uno::Reference<presentation::XTransition> mxTransition;
UnoViewSharedPtr mpView;
TransitionViewPair( uno::Reference<presentation::XTransition> xTransition, const UnoViewSharedPtr pView )
{
mxTransition = xTransition;
mpView = pView;
}
~TransitionViewPair()
{
mxTransition.clear();
mpView.reset();;
}
void update( double t )
{
mxTransition->update( t );
}
};
public:
/** Create a new SlideChanger, for the given leaving and
entering slide bitmaps, which uses super secret OpenGL
stuff.
*/
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) :
SlideChangeBase( leavingSlide_,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maTransitions(),
mbSuccess( false ),
mnTransitionType( nTransitionType ),
mnTransitionSubType( nTransitionSubType ),
mxFactory( xFactory )
{
// create one transition per view
UnoViewVector::const_iterator aCurrView (rViewContainer.begin());
const UnoViewVector::const_iterator aEnd(rViewContainer.end());
while( aCurrView != aEnd )
{
if(! addTransition( *aCurrView ) )
return;
ENSURE_OR_THROW(maTransitions.back() && maTransitions.back()->mxTransition.is(),
"Failed to create plugin transition");
++aCurrView;
}
mbSuccess = true;
}
~PluginSlideChange()
{
mxFactory.clear();
::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
while( aCurrView != aEnd )
{
delete (*aCurrView);
++aCurrView;
}
maTransitions.clear();
}
bool addTransition( const UnoViewSharedPtr& rView )
{
uno::Reference<presentation::XTransition> rTransition = mxFactory->createTransition(
mnTransitionType,
mnTransitionSubType,
rView->getUnoView(),
getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
if( rTransition.is() )
maTransitions.push_back( new TransitionViewPair( rTransition, rView ) );
else
return false;
return true;
}
virtual bool operator()( double t )
{
std::for_each(maTransitions.begin(),
maTransitions.end(),
boost::bind( &TransitionViewPair::update,
_1, t) );
return true;
}
bool Success()
{
return mbSuccess;
}
// ViewEventHandler
virtual void viewAdded( const UnoViewSharedPtr& rView )
{
OSL_TRACE("PluginSlideChange viewAdded");
SlideChangeBase::viewAdded( rView );
::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
bool bKnown = false;
while( aCurrView != aEnd )
{
if( (*aCurrView)->mpView == rView ) {
bKnown = true;
break;
}
++aCurrView;
}
if( !bKnown ) {
OSL_TRACE("need to be added");
addTransition( rView );
}
}
virtual void viewRemoved( const UnoViewSharedPtr& rView )
{
OSL_TRACE("PluginSlideChange viewRemoved");
SlideChangeBase::viewRemoved( rView );
::std::vector< TransitionViewPair* >::iterator aCurrView (maTransitions.begin());
::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
while( aCurrView != aEnd )
{
if( (*aCurrView)->mpView == rView ) {
OSL_TRACE( "view removed" );
delete (*aCurrView);
maTransitions.erase( aCurrView );
break;
}
++aCurrView;
}
}
virtual void viewChanged( const UnoViewSharedPtr& rView )
{
OSL_TRACE("PluginSlideChange viewChanged");
SlideChangeBase::viewChanged( rView );
::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
while( aCurrView != aEnd )
{
if( (*aCurrView)->mpView == rView ) {
OSL_TRACE( "view changed" );
(*aCurrView)->mxTransition->viewChanged( rView->getUnoView(),
getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
} else
OSL_TRACE( "view did not changed" );
++aCurrView;
}
}
virtual void viewsChanged()
{
OSL_TRACE("PluginSlideChange viewsChanged");
SlideChangeBase::viewsChanged();
::std::vector< TransitionViewPair* >::const_iterator aCurrView (maTransitions.begin());
::std::vector< TransitionViewPair* >::const_iterator aEnd(maTransitions.end());
while( aCurrView != aEnd )
{
OSL_TRACE( "view changed" );
(*aCurrView)->mxTransition->viewChanged( (*aCurrView)->mpView->getUnoView(),
getLeavingBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap(),
getEnteringBitmap(ViewEntry((*aCurrView)->mpView))->getXBitmap() );
++aCurrView;
}
}
private:
// One transition object per view
std::vector< TransitionViewPair* > maTransitions;
// bool
bool mbSuccess;
sal_Int16 mnTransitionType;
sal_Int16 mnTransitionSubType;
uno::Reference<presentation::XTransitionFactory> mxFactory;
};
class ClippedSlideChange : public SlideChangeBase
{
public:
/** Create a new SlideChanger, for the given leaving and
entering slide bitmaps, which applies the given clip
polygon.
*/
ClippedSlideChange(
const SlideSharedPtr& pEnteringSlide,
const ParametricPolyPolygonSharedPtr& rPolygon,
const TransitionInfo& rTransitionInfo,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer,
bool bDirectionForward,
const SoundPlayerSharedPtr& pSoundPlayer ) :
SlideChangeBase(
// leaving bitmap is empty, we're leveraging the fact that the
// old slide is still displayed in the background:
boost::optional<SlideSharedPtr>(),
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maClippingFunctor( rPolygon,
rTransitionInfo,
bDirectionForward,
true )
{}
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
private:
ClippingFunctor maClippingFunctor;
};
void ClippedSlideChange::performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
double t )
{
// #i46602# Better work in device coordinate space here,
// otherwise, we too easily suffer from roundoffs. Apart from
// that, getEnteringSizePixel() _guarantees_ to cover the whole
// slide bitmap. There's a catch, though: this removes any effect
// of the view transformation (e.g. rotation) from the transition.
rSprite->setClipPixel(
maClippingFunctor( t,
getEnteringSlideSizePixel(rViewEntry.mpView) ) );
}
void ClippedSlideChange::performOut(
const ::cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
const ViewEntry& /*rViewEntry*/,
const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
double /*t*/ )
{
// not needed here
}
class FadingSlideChange : public SlideChangeBase
{
public:
/** Create a new SlideChanger, for the given leaving and
entering slides, which applies a fade effect.
*/
FadingSlideChange(
boost::optional<SlideSharedPtr> const & leavingSlide,
const SlideSharedPtr& pEnteringSlide,
boost::optional<RGBColor> const& rFadeColor,
const SoundPlayerSharedPtr& pSoundPlayer,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer )
: SlideChangeBase( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maFadeColor( rFadeColor ),
mbFirstTurn( true )
{}
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
private:
const boost::optional< RGBColor > maFadeColor;
bool mbFirstTurn;
};
void FadingSlideChange::performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& /*rViewEntry*/,
const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
double t )
{
ENSURE_OR_THROW(
rSprite,
"FadingSlideChange::performIn(): Invalid sprite" );
if( maFadeColor )
// After half of the active time, fade in new slide
rSprite->setAlpha( t > 0.5 ? 2.0*(t-0.5) : 0.0 );
else
// Fade in new slide over full active time
rSprite->setAlpha( t );
}
void FadingSlideChange::performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t )
{
ENSURE_OR_THROW(
rSprite,
"FadingSlideChange::performOut(): Invalid sprite" );
ENSURE_OR_THROW(
rDestinationCanvas,
"FadingSlideChange::performOut(): Invalid dest canvas" );
// only needed for color fades
if( maFadeColor )
{
if( mbFirstTurn )
{
mbFirstTurn = false;
// clear page to given fade color. 'Leaving' slide is
// painted atop of that, but slowly fading out.
fillPage( rDestinationCanvas,
getEnteringSlideSizePixel( rViewEntry.mpView ),
*maFadeColor );
}
// Until half of the active time, fade out old
// slide. After half of the active time, old slide
// will be invisible.
rSprite->setAlpha( t > 0.5 ? 0.0 : 2.0*(0.5-t) );
}
}
class MovingSlideChange : public SlideChangeBase
{
/// Direction vector for leaving slide,
const ::basegfx::B2DVector maLeavingDirection;
/// Direction vector for entering slide,
const ::basegfx::B2DVector maEnteringDirection;
bool mbFirstPerformCall;
public:
/** Create a new SlideChanger, for the given entering slide
bitmaps, which performes a moving slide change effect
@param rLeavingDirection
Direction vector. The move is performed along this
direction vector, starting at a position where the leaving
slide is fully visible, and ending at a position where the
leaving slide is just not visible. The vector must have
unit length.
@param rEnteringDirection
Direction vector. The move is performed along this
direction vector, starting at a position where the
entering slide is just not visible, and ending at the
final slide position. The vector must have unit length.
*/
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 )
: SlideChangeBase(
leavingSlide, pEnteringSlide, pSoundPlayer,
rViewContainer, rScreenUpdater, rEventMultiplexer,
// Optimization: when leaving bitmap is given,
// but it does not move, don't create sprites for it,
// we simply paint it once at startup:
!rLeavingDirection.equalZero() /* bCreateLeavingSprites */,
!rEnteringDirection.equalZero() /* bCreateEnteringSprites */ ),
// TODO(F1): calc correct length of direction
// vector. Directions not strictly horizontal or vertical
// must travel a longer distance.
maLeavingDirection( rLeavingDirection ),
// TODO(F1): calc correct length of direction
// vector. Directions not strictly horizontal or vertical
// must travel a longer distance.
maEnteringDirection( rEnteringDirection ),
mbFirstPerformCall( true )
{}
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t );
};
void MovingSlideChange::performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t )
{
// intro sprite moves:
ENSURE_OR_THROW(
rSprite,
"MovingSlideChange::performIn(): Invalid sprite" );
ENSURE_OR_THROW(
rDestinationCanvas,
"MovingSlideChange::performIn(): Invalid dest canvas" );
if (mbFirstPerformCall && maLeavingDirection.equalZero())
{
mbFirstPerformCall = false;
renderBitmap( getLeavingBitmap(rViewEntry), rDestinationCanvas );
}
// TODO(F1): This does not account for non-translational
// transformations! If the canvas is rotated, we still
// move the sprite unrotated (which might or might not
// produce the intended effect).
const basegfx::B2DHomMatrix aViewTransform(
rDestinationCanvas->getTransformation() );
const basegfx::B2DPoint aPageOrigin(
aViewTransform * basegfx::B2DPoint() );
// move sprite
rSprite->movePixel(
aPageOrigin +
((t - 1.0) *
::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
maEnteringDirection) );
}
void MovingSlideChange::performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t )
{
// outro sprite moves:
ENSURE_OR_THROW(
rSprite,
"MovingSlideChange::performOut(): Invalid sprite" );
ENSURE_OR_THROW(
rDestinationCanvas,
"MovingSlideChange::performOut(): Invalid dest canvas" );
if (mbFirstPerformCall && maEnteringDirection.equalZero())
{
mbFirstPerformCall = false;
renderBitmap( getEnteringBitmap(rViewEntry), rDestinationCanvas );
}
// TODO(F1): This does not account for non-translational
// transformations! If the canvas is rotated, we still
// move the sprite unrotated (which might or might not
// produce the intended effect).
const basegfx::B2DHomMatrix aViewTransform(
rDestinationCanvas->getTransformation() );
const basegfx::B2DPoint aPageOrigin(
aViewTransform * basegfx::B2DPoint() );
// move sprite
rSprite->movePixel(
aPageOrigin + (t *
::basegfx::B2DSize( getEnteringSlideSizePixel(rViewEntry.mpView) ) *
maLeavingDirection) );
}
NumberAnimationSharedPtr createPushWipeTransition(
boost::optional<SlideSharedPtr> const & leavingSlide_,
const SlideSharedPtr& pEnteringSlide,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer,
sal_Int16 /*nTransitionType*/,
sal_Int16 nTransitionSubType,
bool /*bTransitionDirection*/,
const SoundPlayerSharedPtr& pSoundPlayer )
{
boost::optional<SlideSharedPtr> leavingSlide; // no bitmap
if (leavingSlide_ && (*leavingSlide_).get() != 0)
{
// opt: only page, if we've an
// actual slide to move out here. We
// _don't_ need a fake black background
// bitmap, neither for push nor for comb
// wipes.
leavingSlide = leavingSlide_;
}
// setup direction vector
bool bComb( false );
::basegfx::B2DVector aDirection;
switch( nTransitionSubType )
{
default:
OSL_ENSURE(
false,
"createPushWipeTransition(): Unexpected transition "
"subtype for animations::TransitionType::PUSHWIPE "
"transitions" );
return NumberAnimationSharedPtr();
case animations::TransitionSubType::FROMTOP:
aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
break;
case animations::TransitionSubType::FROMBOTTOM:
aDirection = ::basegfx::B2DVector( 0.0, -1.0 );
break;
case animations::TransitionSubType::FROMLEFT:
aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
break;
case animations::TransitionSubType::FROMRIGHT:
aDirection = ::basegfx::B2DVector( -1.0, 0.0 );
break;
case animations::TransitionSubType::FROMBOTTOMRIGHT:
aDirection = ::basegfx::B2DVector( -1.0, -1.0 );
break;
case animations::TransitionSubType::FROMBOTTOMLEFT:
aDirection = ::basegfx::B2DVector( 1.0, -1.0 );
break;
case animations::TransitionSubType::FROMTOPRIGHT:
aDirection = ::basegfx::B2DVector( -1.0, 1.0 );
break;
case animations::TransitionSubType::FROMTOPLEFT:
aDirection = ::basegfx::B2DVector( 1.0, 1.0 );
break;
case animations::TransitionSubType::COMBHORIZONTAL:
aDirection = ::basegfx::B2DVector( 1.0, 0.0 );
bComb = true;
break;
case animations::TransitionSubType::COMBVERTICAL:
aDirection = ::basegfx::B2DVector( 0.0, 1.0 );
bComb = true;
break;
}
if( bComb )
{
return NumberAnimationSharedPtr(
new CombTransition( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aDirection,
24 /* comb with 12 stripes */ ));
}
else
{
return NumberAnimationSharedPtr(
new MovingSlideChange( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aDirection,
aDirection ));
}
}
NumberAnimationSharedPtr createSlideWipeTransition(
boost::optional<SlideSharedPtr> const & leavingSlide,
const SlideSharedPtr& pEnteringSlide,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer,
sal_Int16 /*nTransitionType*/,
sal_Int16 nTransitionSubType,
bool bTransitionDirection,
const SoundPlayerSharedPtr& pSoundPlayer )
{
// setup 'in' direction vector
::basegfx::B2DVector aInDirection;
switch( nTransitionSubType )
{
default:
OSL_ENSURE(
false,
"createSlideWipeTransition(): Unexpected transition "
"subtype for animations::TransitionType::SLIDEWIPE "
"transitions" );
return NumberAnimationSharedPtr();
case animations::TransitionSubType::FROMTOP:
aInDirection = ::basegfx::B2DVector( 0.0, 1.0 );
break;
case animations::TransitionSubType::FROMRIGHT:
aInDirection = ::basegfx::B2DVector( -1.0, 0.0 );
break;
case animations::TransitionSubType::FROMLEFT:
aInDirection = ::basegfx::B2DVector( 1.0, 0.0 );
break;
case animations::TransitionSubType::FROMBOTTOM:
aInDirection = ::basegfx::B2DVector( 0.0, -1.0 );
break;
case animations::TransitionSubType::FROMBOTTOMRIGHT:
aInDirection = ::basegfx::B2DVector( -1.0, -1.0 );
break;
case animations::TransitionSubType::FROMBOTTOMLEFT:
aInDirection = ::basegfx::B2DVector( 1.0, -1.0 );
break;
case animations::TransitionSubType::FROMTOPRIGHT:
aInDirection = ::basegfx::B2DVector( -1.0, 1.0 );
break;
case animations::TransitionSubType::FROMTOPLEFT:
aInDirection = ::basegfx::B2DVector( 1.0, 1.0 );
break;
}
if( bTransitionDirection )
{
// normal, 'forward' slide wipe effect. Since the old
// content is still on screen (and does not move), we omit
// the 'leaving' slide.
// =======================================================
return NumberAnimationSharedPtr(
new MovingSlideChange(
boost::optional<SlideSharedPtr>() /* no slide */,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
basegfx::B2DVector(),
aInDirection ));
}
else
{
// 'reversed' slide wipe effect. Reverse for slide wipes
// means, that the new slide is in the back, statically,
// and the old one is moving off in the foreground.
// =======================================================
return NumberAnimationSharedPtr(
new MovingSlideChange( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aInDirection,
basegfx::B2DVector() ));
}
}
NumberAnimationSharedPtr 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)
{
PluginSlideChange* pTransition =
new PluginSlideChange(
nTransitionType,
nTransitionSubType,
pLeavingSlide,
pEnteringSlide,
rViewContainer,
rScreenUpdater,
xFactory,
pSoundPlayer,
rEventMultiplexer );
if( pTransition->Success() )
return NumberAnimationSharedPtr( pTransition );
else {
delete pTransition;
return NumberAnimationSharedPtr();
}
}
} // anon namespace
NumberAnimationSharedPtr TransitionFactory::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 )
{
// xxx todo: change to TransitionType::NONE, TransitionSubType::NONE:
if (nTransitionType == 0 && nTransitionSubType == 0) {
// just play sound, no slide transition:
if (pSoundPlayer) {
pSoundPlayer->startPlayback();
// xxx todo: for now, presentation.cxx takes care about the slide
// #i50492# transition sound object, so just release it here
}
return NumberAnimationSharedPtr();
}
ENSURE_OR_THROW(
pEnteringSlide,
"TransitionFactory::createSlideTransition(): Invalid entering slide" );
if( xOptionalFactory.is() &&
xOptionalFactory->hasTransition(nTransitionType, nTransitionSubType) )
{
// #i82460# - optional plugin factory claims this transition. delegate.
NumberAnimationSharedPtr pTransition(
createPluginTransition(
nTransitionType,
nTransitionSubType,
comphelper::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
xOptionalFactory,
pSoundPlayer,
rEventMultiplexer ));
if( pTransition.get() )
return pTransition;
}
const TransitionInfo* pTransitionInfo(
getTransitionInfo( nTransitionType, nTransitionSubType ) );
if( pTransitionInfo != NULL )
{
switch( pTransitionInfo->meTransitionClass )
{
default:
case TransitionInfo::TRANSITION_INVALID:
OSL_TRACE(
"TransitionFactory::createSlideTransition(): "
"Invalid type/subtype (%d/%d) combination encountered.",
nTransitionType,
nTransitionSubType );
return NumberAnimationSharedPtr();
case TransitionInfo::TRANSITION_CLIP_POLYPOLYGON:
{
// generate parametric poly-polygon
ParametricPolyPolygonSharedPtr pPoly(
ParametricPolyPolygonFactory::createClipPolyPolygon(
nTransitionType, nTransitionSubType ) );
// create a clip transition from that
return NumberAnimationSharedPtr(
new ClippedSlideChange( pEnteringSlide,
pPoly,
*pTransitionInfo,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
bTransitionDirection,
pSoundPlayer ));
}
case TransitionInfo::TRANSITION_SPECIAL:
{
switch( nTransitionType )
{
default:
OSL_ENSURE(
false,
"TransitionFactory::createSlideTransition(): "
"Unexpected transition type for "
"TRANSITION_SPECIAL transitions" );
return NumberAnimationSharedPtr();
case animations::TransitionType::RANDOM:
{
// select randomly one of the effects from the
// TransitionFactoryTable
const TransitionInfo* pRandomTransitionInfo(
getRandomTransitionInfo() );
ENSURE_OR_THROW(
pRandomTransitionInfo != NULL,
"TransitionFactory::createSlideTransition(): "
"Got invalid random transition info" );
ENSURE_OR_THROW(
pRandomTransitionInfo->mnTransitionType !=
animations::TransitionType::RANDOM,
"TransitionFactory::createSlideTransition(): "
"Got random again for random input!" );
// and recurse
return createSlideTransition(
pLeavingSlide,
pEnteringSlide,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
xOptionalFactory,
pRandomTransitionInfo->mnTransitionType,
pRandomTransitionInfo->mnTransitionSubType,
bTransitionDirection,
rTransitionFadeColor,
pSoundPlayer );
}
case animations::TransitionType::PUSHWIPE:
{
return createPushWipeTransition(
comphelper::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
nTransitionType,
nTransitionSubType,
bTransitionDirection,
pSoundPlayer );
}
case animations::TransitionType::SLIDEWIPE:
{
return createSlideWipeTransition(
comphelper::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
nTransitionType,
nTransitionSubType,
bTransitionDirection,
pSoundPlayer );
}
case animations::TransitionType::FADE:
{
// black page:
boost::optional<SlideSharedPtr> leavingSlide;
switch( nTransitionSubType )
{
case animations::TransitionSubType::CROSSFADE:
// crossfade needs no further setup,
// just blend new slide over existing
// background.
break;
// TODO(F1): Implement toColor/fromColor fades
case animations::TransitionSubType::FADETOCOLOR:
// FALLTHROUGH intended
case animations::TransitionSubType::FADEFROMCOLOR:
// FALLTHROUGH intended
case animations::TransitionSubType::FADEOVERCOLOR:
if (pLeavingSlide) {
// only generate, if fade
// effect really needs it.
leavingSlide.reset( pLeavingSlide );
}
break;
default:
ENSURE_OR_THROW( false,
"SlideTransitionFactory::createSlideTransition(): Unknown FADE subtype" );
}
return NumberAnimationSharedPtr(
new FadingSlideChange(
leavingSlide,
pEnteringSlide,
comphelper::make_optional(
rTransitionFadeColor),
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ));
}
}
}
break;
}
}
// No animation generated, maybe no table entry for given
// transition?
OSL_TRACE(
"TransitionFactory::createSlideTransition(): "
"Unknown type/subtype (%d/%d) combination encountered",
nTransitionType,
nTransitionSubType );
OSL_ENSURE(
false,
"TransitionFactory::createSlideTransition(): "
"Unknown type/subtype combination encountered" );
return NumberAnimationSharedPtr();
}
} // namespace internal
} // namespace presentation