/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* 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 .
*/
#include <comphelper/diagnose_ex.hxx>
#include <sal/log.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <cppcanvas/customsprite.hxx>
#include <com/sun/star/animations/TransitionType.hpp>
#include <com/sun/star/animations/TransitionSubType.hpp>
#include "slidechangebase.hxx"
#include <transitionfactory.hxx>
#include "transitionfactorytab.hxx"
#include "parametricpolypolygonfactory.hxx"
#include "clippingfunctor.hxx"
#include "combtransition.hxx"
#include <tools.hxx>
#include <memory>
#include <utility>
/***************************************************
*** ***
*** Slide Transition Effects ***
*** ***
***************************************************/
using namespace com::sun::star;
namespace slideshow::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.getWidth(),
aOutputPosPixel.getY() + rPageSizePixel.getHeight() ),
rFillColor.getIntegerColor() );
}
class PluginSlideChange: public SlideChangeBase
{
struct TransitionViewPair {
uno::Reference<presentation::XTransition> mxTransition;
UnoViewSharedPtr mpView;
TransitionViewPair( uno::Reference<presentation::XTransition> xTransition, UnoViewSharedPtr xView )
: mxTransition(std::move(xTransition)), mpView(std::move(xView))
{
}
~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,
const RGBColor& rTransitionFadeColor,
std::optional<SlideSharedPtr> const& leavingSlide_,
const SlideSharedPtr& pEnteringSlide,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
uno::Reference<
presentation::XTransitionFactory> xFactory,
const SoundPlayerSharedPtr& pSoundPlayer,
EventMultiplexer& rEventMultiplexer) :
SlideChangeBase( leavingSlide_,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maTransitions(),
mbSuccess( false ),
mnTransitionType( nTransitionType ),
mnTransitionSubType( nTransitionSubType ),
mnTransitionFadeColor( rTransitionFadeColor ),
mxFactory(std::move( xFactory ))
{
// create one transition per view
for( const auto& rView : rViewContainer )
{
if( !addTransition( rView ) )
return;
ENSURE_OR_THROW(maTransitions.back() && maTransitions.back()->mxTransition.is(),
"Failed to create plugin transition");
}
mbSuccess = true;
}
virtual ~PluginSlideChange() override
{
mxFactory.clear();
}
bool addTransition( const UnoViewSharedPtr& rView )
{
uno::Reference<presentation::XTransition> rTransition = mxFactory->createTransition(
mnTransitionType,
mnTransitionSubType,
RGBAColor2UnoColor( mnTransitionFadeColor.getIntegerColor()),
rView->getUnoView(),
getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
if( rTransition.is() )
maTransitions.emplace_back( new TransitionViewPair( rTransition, rView ) );
else
return false;
return true;
}
virtual bool operator()( double t ) override
{
for( const auto& pTransition : maTransitions )
pTransition->update( t );
return true;
}
bool Success()
{
return mbSuccess;
}
// ViewEventHandler
virtual void viewAdded( const UnoViewSharedPtr& rView ) override
{
SAL_INFO("slideshow", "PluginSlideChange viewAdded");
SlideChangeBase::viewAdded( rView );
for( const auto& pCurrView : maTransitions )
{
if( pCurrView->mpView == rView )
return;
}
SAL_INFO("slideshow", "need to be added" );
addTransition( rView );
}
virtual void viewRemoved( const UnoViewSharedPtr& rView ) override
{
SAL_INFO("slideshow", "PluginSlideChange viewRemoved");
SlideChangeBase::viewRemoved( rView );
auto aIter = std::find_if(maTransitions.begin(), maTransitions.end(),
[&rView](const std::unique_ptr<TransitionViewPair>& rxTransition) { return rxTransition->mpView == rView; });
if (aIter != maTransitions.end())
{
SAL_INFO("slideshow", "view removed" );
maTransitions.erase( aIter );
}
}
virtual void viewChanged( const UnoViewSharedPtr& rView ) override
{
SAL_INFO("slideshow", "PluginSlideChange viewChanged");
SlideChangeBase::viewChanged( rView );
for( const auto& pCurrView : maTransitions )
{
if( pCurrView->mpView == rView )
{
SAL_INFO("slideshow", "view changed" );
pCurrView->mxTransition->viewChanged( rView->getUnoView(),
getLeavingBitmap(ViewEntry(rView))->getXBitmap(),
getEnteringBitmap(ViewEntry(rView))->getXBitmap() );
}
else
SAL_INFO("slideshow", "view did not change" );
}
}
virtual void viewsChanged() override
{
SAL_INFO("slideshow", "PluginSlideChange viewsChanged");
SlideChangeBase::viewsChanged();
for( const auto& pCurrView : maTransitions )
{
SAL_INFO("slideshow", "view changed" );
UnoViewSharedPtr pView = pCurrView->mpView;
pCurrView->mxTransition->viewChanged( pView->getUnoView(),
getLeavingBitmap(ViewEntry(pView))->getXBitmap(),
getEnteringBitmap(ViewEntry(pView))->getXBitmap() );
}
}
private:
// One transition object per view
std::vector< std::unique_ptr<TransitionViewPair> > maTransitions;
// bool
bool mbSuccess;
sal_Int16 mnTransitionType;
sal_Int16 mnTransitionSubType;
RGBColor mnTransitionFadeColor;
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:
std::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 ) override;
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
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,
::basegfx::B2DSize( 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(
std::optional<SlideSharedPtr> const & leavingSlide,
const SlideSharedPtr& pEnteringSlide,
std::optional<RGBColor> const& rFadeColor,
const SoundPlayerSharedPtr& pSoundPlayer,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer )
: SlideChangeBase( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maFadeColor( rFadeColor )
{}
virtual void prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas ) override;
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
private:
const std::optional< RGBColor > maFadeColor;
};
void FadingSlideChange::prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas )
{
if ( maFadeColor )
{
// clear page to given fade color. 'Leaving' slide is
// painted atop of that, but slowly fading out.
fillPage( rDestinationCanvas,
::basegfx::B2DSize( getEnteringSlideSizePixel( rViewEntry.mpView ) ),
*maFadeColor );
}
}
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 )
{
// 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 CutSlideChange : public SlideChangeBase
{
public:
/** Create a new SlideChanger, for the given leaving and
entering slides, which applies a cut effect.
*/
CutSlideChange(
std::optional<SlideSharedPtr> const & leavingSlide,
const SlideSharedPtr& pEnteringSlide,
const RGBColor& rFadeColor,
const SoundPlayerSharedPtr& pSoundPlayer,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
EventMultiplexer& rEventMultiplexer )
: SlideChangeBase( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer ),
maFadeColor( rFadeColor )
{}
virtual void prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas ) override;
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
private:
RGBColor maFadeColor;
};
void CutSlideChange::prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas )
{
// clear page to given fade color. 'Leaving' slide is
// painted atop of that
fillPage( rDestinationCanvas,
::basegfx::B2DSize( getEnteringSlideSizePixel( rViewEntry.mpView ) ),
maFadeColor );
}
void CutSlideChange::performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& /*rViewEntry*/,
const ::cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
double t )
{
ENSURE_OR_THROW(
rSprite,
"CutSlideChange::performIn(): Invalid sprite" );
// After 2/3rd of the active time, display new slide
rSprite->setAlpha( t > 2/3.0 ? 1.0 : 0.0 );
}
void CutSlideChange::performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& /* rViewEntry */,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t )
{
ENSURE_OR_THROW(
rSprite,
"CutSlideChange::performOut(): Invalid sprite" );
ENSURE_OR_THROW(
rDestinationCanvas,
"CutSlideChange::performOut(): Invalid dest canvas" );
// Until 1/3rd of the active time, display old slide.
rSprite->setAlpha( t > 1/3.0 ? 0.0 : 1.0 );
}
class MovingSlideChange : public SlideChangeBase
{
/// Direction vector for leaving slide,
const ::basegfx::B2DVector maLeavingDirection;
/// Direction vector for entering slide,
const ::basegfx::B2DVector maEnteringDirection;
public:
/** Create a new SlideChanger, for the given entering slide
bitmaps, which performs 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 std::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 )
{}
virtual void prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas ) override;
virtual void performIn(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
virtual void performOut(
const ::cppcanvas::CustomSpriteSharedPtr& rSprite,
const ViewEntry& rViewEntry,
const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas,
double t ) override;
};
void MovingSlideChange::prepareForRun(
const ViewEntry& rViewEntry,
const cppcanvas::CanvasSharedPtr& rDestinationCanvas )
{
if ( maLeavingDirection.equalZero() )
renderBitmap( getLeavingBitmap( rViewEntry ), rDestinationCanvas );
else if ( maEnteringDirection.equalZero() )
renderBitmap( getEnteringBitmap( rViewEntry ), rDestinationCanvas );
}
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" );
// 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
auto aSlideSizePixel = getEnteringSlideSizePixel(rViewEntry.mpView);
rSprite->movePixel(
aPageOrigin +
((t - 1.0) *
basegfx::B2DVector( aSlideSizePixel.getWidth(), aSlideSizePixel.getHeight()) *
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" );
// 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
auto aSlideSizePixel = getEnteringSlideSizePixel(rViewEntry.mpView);
rSprite->movePixel(
aPageOrigin + (t *
basegfx::B2DVector(aSlideSizePixel.getWidth(), aSlideSizePixel.getHeight()) *
maLeavingDirection) );
}
NumberAnimationSharedPtr createPushWipeTransition(
std::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 )
{
std::optional<SlideSharedPtr> leavingSlide; // no bitmap
if (leavingSlide_ && *leavingSlide_ != nullptr)
{
// 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_FAIL(
"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 std::make_shared<CombTransition>( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aDirection,
24 /* comb with 12 stripes */ );
}
else
{
return std::make_shared<MovingSlideChange>( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aDirection,
aDirection );
}
}
NumberAnimationSharedPtr createSlideWipeTransition(
std::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_FAIL(
"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 std::make_shared<MovingSlideChange>(
std::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 std::make_shared<MovingSlideChange>( leavingSlide,
pEnteringSlide,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
aInDirection,
basegfx::B2DVector() );
}
}
NumberAnimationSharedPtr createPluginTransition(
sal_Int16 nTransitionType,
sal_Int16 nTransitionSubType,
const RGBColor& rTransitionFadeColor,
std::optional<SlideSharedPtr> const& pLeavingSlide,
const SlideSharedPtr& pEnteringSlide,
const UnoViewContainer& rViewContainer,
ScreenUpdater& rScreenUpdater,
const uno::Reference<
presentation::XTransitionFactory>& xFactory,
const SoundPlayerSharedPtr& pSoundPlayer,
EventMultiplexer& rEventMultiplexer)
{
auto pTransition =
std::make_shared<PluginSlideChange>(
nTransitionType,
nTransitionSubType,
rTransitionFadeColor,
pLeavingSlide,
pEnteringSlide,
rViewContainer,
rScreenUpdater,
xFactory,
pSoundPlayer,
rEventMultiplexer );
if( !pTransition->Success() )
return nullptr;
return pTransition;
}
} // 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,
rTransitionFadeColor,
std::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
xOptionalFactory,
pSoundPlayer,
rEventMultiplexer ));
if( pTransition )
return pTransition;
}
const TransitionInfo* pTransitionInfo(
getTransitionInfo( nTransitionType, nTransitionSubType ) );
if( pTransitionInfo != nullptr )
{
switch( pTransitionInfo->meTransitionClass )
{
default:
case TransitionInfo::TRANSITION_INVALID:
SAL_WARN("slideshow",
"TransitionFactory::createSlideTransition(): "
"Invalid type/subtype 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 std::make_shared<ClippedSlideChange>( pEnteringSlide,
pPoly,
*pTransitionInfo,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
bTransitionDirection,
pSoundPlayer );
}
case TransitionInfo::TRANSITION_SPECIAL:
{
switch( nTransitionType )
{
default:
OSL_FAIL(
"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 != nullptr,
"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(
std::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
nTransitionType,
nTransitionSubType,
bTransitionDirection,
pSoundPlayer );
}
case animations::TransitionType::SLIDEWIPE:
{
return createSlideWipeTransition(
std::make_optional(pLeavingSlide),
pEnteringSlide,
rViewContainer,
rScreenUpdater,
rEventMultiplexer,
nTransitionType,
nTransitionSubType,
bTransitionDirection,
pSoundPlayer );
}
case animations::TransitionType::BARWIPE:
case animations::TransitionType::FADE:
{
// black page:
std::optional<SlideSharedPtr> leavingSlide;
std::optional<RGBColor> aFadeColor;
switch( nTransitionSubType )
{
case animations::TransitionSubType::CROSSFADE:
// crossfade needs no further setup,
// just blend new slide over current
// slide.
break;
// TODO(F1): Implement toColor/fromColor fades
case animations::TransitionSubType::FADETOCOLOR:
case animations::TransitionSubType::FADEFROMCOLOR:
case animations::TransitionSubType::FADEOVERCOLOR:
if (pLeavingSlide) {
// only generate, if fade
// effect really needs it.
leavingSlide = pLeavingSlide;
}
aFadeColor = rTransitionFadeColor;
break;
default:
ENSURE_OR_THROW( false,
"SlideTransitionFactory::createSlideTransition(): Unknown FADE subtype" );
}
if( nTransitionType == animations::TransitionType::FADE )
return std::make_shared<FadingSlideChange>(
leavingSlide,
pEnteringSlide,
aFadeColor,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer );
else
return std::make_shared<CutSlideChange>(
leavingSlide,
pEnteringSlide,
rTransitionFadeColor,
pSoundPlayer,
rViewContainer,
rScreenUpdater,
rEventMultiplexer );
}
}
}
break;
}
}
// No animation generated, maybe no table entry for given
// transition?
SAL_WARN("slideshow",
"TransitionFactory::createSlideTransition(): "
"Unknown type/subtype combination encountered "
<< nTransitionType << " " << nTransitionSubType );
OSL_FAIL(
"TransitionFactory::createSlideTransition(): "
"Unknown type/subtype combination encountered" );
return NumberAnimationSharedPtr();
}
} // namespace presentation
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1023 A pointer without owner is added to the 'maTransitions' container by the 'emplace_back' method. A memory leak will occur in case of an exception.