summaryrefslogtreecommitdiff
path: root/slideshow/source/engine/transitions/slidechangebase.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'slideshow/source/engine/transitions/slidechangebase.cxx')
-rw-r--r--slideshow/source/engine/transitions/slidechangebase.cxx535
1 files changed, 535 insertions, 0 deletions
diff --git a/slideshow/source/engine/transitions/slidechangebase.cxx b/slideshow/source/engine/transitions/slidechangebase.cxx
new file mode 100644
index 000000000000..466052b67900
--- /dev/null
+++ b/slideshow/source/engine/transitions/slidechangebase.cxx
@@ -0,0 +1,535 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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 <canvas/canvastools.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <cppcanvas/basegfxfactory.hxx>
+
+#include "slidechangebase.hxx"
+#include "tools.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+using namespace com::sun::star;
+
+namespace slideshow {
+namespace internal {
+
+SlideChangeBase::SlideChangeBase( boost::optional<SlideSharedPtr> const & leavingSlide,
+ const SlideSharedPtr& pEnteringSlide,
+ const SoundPlayerSharedPtr& pSoundPlayer,
+ const UnoViewContainer& rViewContainer,
+ ScreenUpdater& rScreenUpdater,
+ EventMultiplexer& rEventMultiplexer,
+ bool bCreateLeavingSprites,
+ bool bCreateEnteringSprites ) :
+ mpSoundPlayer( pSoundPlayer ),
+ mrEventMultiplexer(rEventMultiplexer),
+ mrScreenUpdater(rScreenUpdater),
+ maLeavingSlide( leavingSlide ),
+ mpEnteringSlide( pEnteringSlide ),
+ maViewData(),
+ mrViewContainer(rViewContainer),
+ mbCreateLeavingSprites(bCreateLeavingSprites),
+ mbCreateEnteringSprites(bCreateEnteringSprites),
+ mbSpritesVisible(false),
+ mbFinished(false),
+ mbPrefetched(false)
+{
+ ENSURE_OR_THROW(
+ pEnteringSlide,
+ "SlideChangeBase::SlideChangeBase(): Invalid entering slide!" );
+}
+
+SlideBitmapSharedPtr SlideChangeBase::getLeavingBitmap( const ViewEntry& rViewEntry ) const
+{
+ if( !rViewEntry.mpLeavingBitmap )
+ rViewEntry.mpLeavingBitmap = createBitmap(rViewEntry.mpView,
+ maLeavingSlide);
+
+ return rViewEntry.mpLeavingBitmap;
+}
+
+SlideBitmapSharedPtr SlideChangeBase::getEnteringBitmap( const ViewEntry& rViewEntry ) const
+{
+ if( !rViewEntry.mpEnteringBitmap )
+ rViewEntry.mpEnteringBitmap = createBitmap( rViewEntry.mpView,
+ boost::optional<SlideSharedPtr>(mpEnteringSlide) );
+
+ return rViewEntry.mpEnteringBitmap;
+}
+
+SlideBitmapSharedPtr SlideChangeBase::createBitmap( const UnoViewSharedPtr& rView,
+ const boost::optional<SlideSharedPtr>& rSlide ) const
+{
+ SlideBitmapSharedPtr pRet;
+ if( !rSlide )
+ return pRet;
+
+ SlideSharedPtr const & pSlide = *rSlide;
+ if( !pSlide )
+ {
+ // TODO(P3): No need to generate a bitmap here. This only made
+ // the code more uniform. Faster would be to simply clear the
+ // sprite to black.
+
+ // create empty, black-filled bitmap
+ const basegfx::B2ISize slideSizePixel(
+ getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ rView ));
+
+ cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() );
+
+ // create a bitmap of appropriate size
+ cppcanvas::BitmapSharedPtr pBitmap(
+ cppcanvas::BaseGfxFactory::getInstance().createBitmap(
+ pCanvas,
+ slideSizePixel ) );
+
+ ENSURE_OR_THROW(
+ pBitmap,
+ "SlideChangeBase::createBitmap(): Cannot create page bitmap" );
+
+ cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas(
+ pBitmap->getBitmapCanvas() );
+
+ ENSURE_OR_THROW( pBitmapCanvas,
+ "SlideChangeBase::createBitmap(): "
+ "Cannot create page bitmap canvas" );
+
+ // set transformation to identitiy (->device pixel)
+ pBitmapCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
+
+ // clear bitmap to black
+ fillRect( pBitmapCanvas,
+ ::basegfx::B2DRectangle( 0.0, 0.0,
+ slideSizePixel.getX(),
+ slideSizePixel.getY() ),
+ 0x000000FFU );
+
+ pRet.reset( new SlideBitmap( pBitmap ));
+ }
+ else
+ {
+ pRet = pSlide->getCurrentSlideBitmap( rView );
+ }
+
+ return pRet;
+}
+
+::basegfx::B2ISize SlideChangeBase::getEnteringSlideSizePixel( const UnoViewSharedPtr& pView ) const
+{
+ return getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ pView );
+}
+
+::basegfx::B2ISize SlideChangeBase::getLeavingSlideSizePixel( const UnoViewSharedPtr& pView ) const
+{
+ return getSlideSizePixel( (*maLeavingSlide)->getSlideSize(),
+ pView );
+}
+
+
+void SlideChangeBase::renderBitmap(
+ SlideBitmapSharedPtr const & pSlideBitmap,
+ cppcanvas::CanvasSharedPtr const & pCanvas )
+{
+ if( pSlideBitmap && pCanvas )
+ {
+ // need to render without any transformation (we
+ // assume device units):
+ const basegfx::B2DHomMatrix viewTransform(
+ pCanvas->getTransformation() );
+ const basegfx::B2DPoint pageOrigin(
+ viewTransform * basegfx::B2DPoint() );
+ const cppcanvas::CanvasSharedPtr pDevicePixelCanvas(
+ pCanvas->clone() );
+
+ // render at output position, don't modify bitmap object (no move!):
+ const basegfx::B2DHomMatrix transform(basegfx::tools::createTranslateB2DHomMatrix(
+ pageOrigin.getX(), pageOrigin.getY()));
+
+ pDevicePixelCanvas->setTransformation( transform );
+ pSlideBitmap->draw( pDevicePixelCanvas );
+ }
+}
+
+void SlideChangeBase::prefetch( const AnimatableShapeSharedPtr&,
+ const ShapeAttributeLayerSharedPtr& )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished || mbPrefetched )
+ return;
+
+ // register ourselves for view change events
+ mrEventMultiplexer.addViewHandler( shared_from_this() );
+
+ // init views and create slide bitmaps
+ std::for_each( mrViewContainer.begin(),
+ mrViewContainer.end(),
+ boost::bind( &SlideChangeBase::viewAdded,
+ this,
+ _1 ));
+
+ mbPrefetched = true;
+}
+
+void SlideChangeBase::start( const AnimatableShapeSharedPtr& rShape,
+ const ShapeAttributeLayerSharedPtr& rLayer )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ prefetch(rShape,rLayer); // no-op, if already done
+
+ // start accompanying sound effect, if any
+ if( mpSoundPlayer )
+ {
+ mpSoundPlayer->startPlayback();
+ // xxx todo: for now, presentation.cxx takes care about the slide
+ // #i50492# transition sound object, so just release it here
+ mpSoundPlayer.reset();
+ }
+}
+
+void SlideChangeBase::end()
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ try
+ {
+ // draw fully entered bitmap:
+ ViewsVecT::const_iterator aCurr( beginViews() );
+ const ViewsVecT::const_iterator aEnd( endViews() );
+ while( aCurr != aEnd )
+ {
+ // fully clear view content to background color
+ aCurr->mpView->clearAll();
+
+ const SlideBitmapSharedPtr pSlideBitmap( getEnteringBitmap( *aCurr ));
+ pSlideBitmap->clip( basegfx::B2DPolyPolygon() /* no clipping */ );
+ renderBitmap( pSlideBitmap,
+ aCurr->mpView->getCanvas() );
+
+ ++aCurr;
+ }
+ }
+ catch( uno::Exception& )
+ {
+ // make sure releasing below happens
+ }
+
+ // swap changes to screen
+ mrScreenUpdater.notifyUpdate();
+
+ // make object dysfunctional
+ mbFinished = true;
+ ViewsVecT().swap(maViewData);
+ maLeavingSlide.reset();
+ mpEnteringSlide.reset();
+
+ // sprites have been binned above
+ mbSpritesVisible = false;
+
+ // remove also from event multiplexer, we're dead anyway
+ mrEventMultiplexer.removeViewHandler( shared_from_this() );
+}
+
+bool SlideChangeBase::operator()( double nValue )
+{
+ if( mbFinished )
+ return false;
+
+ const std::size_t nEntries( maViewData.size() );
+ bool bSpritesVisible( mbSpritesVisible );
+
+ for( ::std::size_t i=0; i<nEntries; ++i )
+ {
+ // calc sprite offsets. The enter/leaving bitmaps are only
+ // as large as the actual slides. For scaled-down
+ // presentations, we have to move the left, top edge of
+ // those bitmaps to the actual position, governed by the
+ // given view transform. The aSpritePosPixel local
+ // variable is already in device coordinate space
+ // (i.e. pixel).
+
+ ViewEntry& rViewEntry( maViewData[i] );
+ const ::cppcanvas::CanvasSharedPtr& rCanvas( rViewEntry.mpView->getCanvas() );
+ ::cppcanvas::CustomSpriteSharedPtr& rInSprite( rViewEntry.mpInSprite );
+ ::cppcanvas::CustomSpriteSharedPtr& rOutSprite( rViewEntry.mpOutSprite );
+
+ // TODO(F2): Properly respect clip here.
+
+ // Might have to be transformed, too.
+ const ::basegfx::B2DHomMatrix aViewTransform(
+ rViewEntry.mpView->getTransformation() );
+ const ::basegfx::B2DPoint aSpritePosPixel(
+ aViewTransform * ::basegfx::B2DPoint() );
+
+ // move sprite to final output position, in
+ // device coordinates
+ if( rOutSprite )
+ rOutSprite->movePixel( aSpritePosPixel );
+ if( rInSprite )
+ rInSprite->movePixel( aSpritePosPixel );
+
+ if( !mbSpritesVisible )
+ {
+ if( rOutSprite )
+ {
+ // only render once: clipping is done
+ // exclusively with the sprite
+ const ::cppcanvas::CanvasSharedPtr pOutContentCanvas(
+ rOutSprite->getContentCanvas() );
+ if( pOutContentCanvas)
+ {
+ // TODO(Q2): Use basegfx bitmaps here
+
+ // TODO(F1): SlideBitmap is not fully portable
+ // between different canvases!
+
+ // render the content
+ OSL_ASSERT( getLeavingBitmap( rViewEntry ) );
+ if( getLeavingBitmap( rViewEntry ) )
+ getLeavingBitmap( rViewEntry )->draw( pOutContentCanvas );
+ }
+ }
+
+ if( rInSprite )
+ {
+ // only render once: clipping is done
+ // exclusively with the sprite
+ const ::cppcanvas::CanvasSharedPtr pInContentCanvas(
+ rInSprite->getContentCanvas() );
+ if( pInContentCanvas )
+ {
+ // TODO(Q2): Use basegfx bitmaps here
+
+ // TODO(F1): SlideBitmap is not fully portable
+ // between different canvases!
+
+ // render the content
+ getEnteringBitmap( rViewEntry )->draw( pInContentCanvas );
+ }
+ }
+ }
+
+ if( rOutSprite )
+ performOut( rOutSprite, rViewEntry, rCanvas, nValue );
+ if( rInSprite )
+ performIn( rInSprite, rViewEntry, rCanvas, nValue );
+
+ // finishing deeds for first run.
+ if( !mbSpritesVisible)
+ {
+ // enable sprites:
+ if( rOutSprite )
+ rOutSprite->show();
+ if( rInSprite )
+ rInSprite->show();
+ bSpritesVisible = true;
+ }
+ } // for_each( sprite )
+
+ mbSpritesVisible = bSpritesVisible;
+ mrScreenUpdater.notifyUpdate();
+
+ return true;
+}
+
+void SlideChangeBase::performIn(
+ const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
+ const ViewEntry& /*rViewEntry*/,
+ const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double /*t*/ )
+{
+}
+
+void SlideChangeBase::performOut(
+ const cppcanvas::CustomSpriteSharedPtr& /*rSprite*/,
+ const ViewEntry& /*rViewEntry*/,
+ const cppcanvas::CanvasSharedPtr& /*rDestinationCanvas*/,
+ double /*t*/ )
+{
+}
+
+double SlideChangeBase::getUnderlyingValue() const
+{
+ return 0.0; // though this should be used in concert with
+ // ActivitiesFactory::createSimpleActivity, better
+ // explicitely name our start value.
+ // Permissible range for operator() above is [0,1]
+}
+
+void SlideChangeBase::viewAdded( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ maViewData.push_back( ViewEntry(rView) );
+
+ ViewEntry& rEntry( maViewData.back() );
+ getEnteringBitmap( rEntry );
+ getLeavingBitmap( rEntry );
+ addSprites( rEntry );
+}
+
+void SlideChangeBase::viewRemoved( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ // erase corresponding entry from maViewData
+ maViewData.erase(
+ std::remove_if(
+ maViewData.begin(),
+ maViewData.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( &ViewEntry::getView, _1 ))),
+ maViewData.end() );
+}
+
+void SlideChangeBase::viewChanged( const UnoViewSharedPtr& rView )
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ // find entry corresponding to modified view
+ ViewsVecT::iterator aModifiedEntry(
+ std::find_if(
+ maViewData.begin(),
+ maViewData.end(),
+ boost::bind(
+ std::equal_to<UnoViewSharedPtr>(),
+ rView,
+ // select view:
+ boost::bind( &ViewEntry::getView, _1 ) )));
+
+ OSL_ASSERT( aModifiedEntry != maViewData.end() );
+ if( aModifiedEntry == maViewData.end() )
+ return;
+
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ clearViewEntry( *aModifiedEntry );
+ addSprites( *aModifiedEntry );
+}
+
+void SlideChangeBase::viewsChanged()
+{
+ // we're a one-shot activity, and already finished
+ if( mbFinished )
+ return;
+
+ ViewsVecT::iterator aIter( maViewData.begin() );
+ ViewsVecT::iterator const aEnd ( maViewData.end() );
+ while( aIter != aEnd )
+ {
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ clearViewEntry( *aIter );
+ addSprites( *aIter );
+
+ ++aIter;
+ }
+}
+
+cppcanvas::CustomSpriteSharedPtr SlideChangeBase::createSprite(
+ UnoViewSharedPtr const & pView,
+ basegfx::B2DSize const & rSpriteSize,
+ double nPrio ) const
+{
+ // TODO(P2): change to bitmapsprite once that's working
+ const cppcanvas::CustomSpriteSharedPtr pSprite(
+ pView->createSprite( rSpriteSize,
+ nPrio ));
+
+ // alpha default is 0.0, which seems to be
+ // a bad idea when viewing content...
+ pSprite->setAlpha( 1.0 );
+ if (mbSpritesVisible)
+ pSprite->show();
+
+ return pSprite;
+}
+
+void SlideChangeBase::addSprites( ViewEntry& rEntry )
+{
+ if( mbCreateLeavingSprites && maLeavingSlide )
+ {
+ // create leaving sprite:
+ const basegfx::B2ISize leavingSlideSizePixel(
+ getLeavingBitmap( rEntry )->getSize() );
+
+ rEntry.mpOutSprite = createSprite( rEntry.mpView,
+ leavingSlideSizePixel,
+ 100 );
+ }
+
+ if( mbCreateEnteringSprites )
+ {
+ // create entering sprite:
+ const basegfx::B2ISize enteringSlideSizePixel(
+ getSlideSizePixel( mpEnteringSlide->getSlideSize(),
+ rEntry.mpView ));
+
+ rEntry.mpInSprite = createSprite( rEntry.mpView,
+ enteringSlideSizePixel,
+ 101 );
+ }
+}
+
+void SlideChangeBase::clearViewEntry( ViewEntry& rEntry )
+{
+ // clear stale info (both bitmaps and sprites prolly need a
+ // resize)
+ rEntry.mpEnteringBitmap.reset();
+ rEntry.mpLeavingBitmap.reset();
+ rEntry.mpInSprite.reset();
+ rEntry.mpOutSprite.reset();
+}
+
+} // namespace internal
+} // namespace presentation