diff options
author | Oliver Bolte <obo@openoffice.org> | 2007-07-17 13:57:53 +0000 |
---|---|---|
committer | Oliver Bolte <obo@openoffice.org> | 2007-07-17 13:57:53 +0000 |
commit | 4f62fb23245bb1666988bdc08b361124dd788c43 (patch) | |
tree | f4747704e874c01e6899f01e32d0a9cdcdaddde7 /slideshow/source/engine/slide | |
parent | 67b029256ddf4842daa8ea6781f47b703cdaa756 (diff) |
INTEGRATION: CWS presfixes12 (1.1.2); FILE ADDED
2007/05/14 00:55:29 thb 1.1.2.14: #i77154# Moved intrinsic animation notification from global EventMultiplexer to ShapeManager (which is local to each slide). This is a temporary workaround, the proper fix would demote the EventMultiplexer to each Slide
2007/05/10 20:32:40 thb 1.1.2.13: #i37778# Reworked LayerManager::updateShapeLayers - now much better aligned with general shape update, and avoids superfluous rendering; made unit tests work again; passing down slide background repaint status to LayerManager; relaxed preconditions for Shape::getUpdateArea() - no longer requires views to work; now catching singular view matrix and using sensible default at API border
2007/05/02 21:37:23 thb 1.1.2.12: #i37778# Changed calls to cppcanvas::Canvas::getTransformation() to ViewLayer::getTransformation() where appropriate (because that's more direct); added initial Slide rendering back in (this time optional)
2007/04/30 07:26:33 thb 1.1.2.11: #i37778# Rendering slide bitmap at the end of a slide transition, instead of during Slide::show(), to avoid temporary display of previous slide after transition sprite vanished.
2007/03/11 00:17:59 thb 1.1.2.10: #i37778# Necessary adaptions for cppcanvas clip behaviour (extra setClip() methods to clear clip, instead of empty polygon, which denotes everything clipped on canvas); removed cyclic references for intrinsically animated shapes (GIF and drawing layer scroll text); fixed a few coding style inconsistencies
2007/03/06 21:54:18 thb 1.1.2.9: #i37778# Added bool property to disable z order correct animations
2007/02/25 01:10:27 thb 1.1.2.8: #i37778# Cleared up error handling a lot: no longer quenching RuntimeExceptions; reporting assertions in the debug case; ViewLayer now reports resized sprite (which needs re-render from all shapes); fixed missing subset area reduction for glyph-level animations; added return of resize state from Layer::commitLayerBounds(); adapted unit tests to corrected behaviour
2007/02/20 22:41:15 thb 1.1.2.7: #i37778# Emulating old sprite behaviour to clear content on getContentCanvas() in AnimatedSprite; corrected handling of full and partial view clears; corrected layer update when shapes are added or removed
2007/02/12 02:14:52 thb 1.1.2.6: #i37778# Added workaround to have ViewLayer always return valid canvas (even if no size has been set); fixed silly reference-instead-of-byvalue bug in SlideAnimations for slide size; fixed member initialization order problem in SlideImpl (also affecting slide size); adapted shape import for new LayerManager (which no longer gracefully ignores addition of NULL shapes); extended unit tests to catch fixed bugs
2007/02/06 17:18:13 thb 1.1.2.5: #i37778# Moved clear() method from View to ViewLayer (also sprites need to be cleared); fixed a few more cases of local code style violations; removed redundant inline keywords; finished Layer/LayerManager rework (Layer now represents ViewLayers, shapes and rendering are fully under LayerManager control); made shape comparator reusable
2007/01/31 14:30:33 thb 1.1.2.4: #i37778# removed View::isContentDestroyed() and mbContentValid distinction on View::clear() - clear() now always clears view the hard way; added explicit screen update to CombTransition, which bypasses SlideChangeBase functionality
2007/01/30 16:43:50 thb 1.1.2.3: #i37778# Made view update/repaint/resize work again; swapped BackgroundShape parameters for correct mtf import
2007/01/29 16:29:30 thb 1.1.2.2: #i37778# Build fixes for msvc; added shapes lib to util link line
2007/01/29 14:02:15 thb 1.1.2.1: Issue number: #i37778#
Larger slideshow refactoring. Wrote design and coding style manifest,
and adapted the code to actually conform to this. In detail:
- cleaned up ownership/disposable/weak_ptr story. removed hacks and
explicit Disposable implementations, where workaround were available
- removed object mutices, where superfluous
- reworked EventMultiplexer (using templatized listener class now), added
more events. EventMultiplexer now serves as a true blackboard
- reworked directory structure: disjunct parts are now physically separated
into directories, instantiation happens via factories & abstract interfaces
- added CursorManager, to make setting mouse cursor less hackish
- reworked DrawShape, to implement SeparateListener pattern
- reworked IntrinsicAnimationActivity, to avoid cyclic references
- modified hyperlink & shape cursor handling to communicate via
EventMultiplexer
- renamed & cleaned up files (presentation.cxx now named slideshowimpl.cxx,
etc.)
- added first version of the z-order fix to layer/layermanager
- cleaned up include guards and include syntax
Diffstat (limited to 'slideshow/source/engine/slide')
-rw-r--r-- | slideshow/source/engine/slide/slideimpl.cxx | 1215 |
1 files changed, 1215 insertions, 0 deletions
diff --git a/slideshow/source/engine/slide/slideimpl.cxx b/slideshow/source/engine/slide/slideimpl.cxx new file mode 100644 index 000000000000..9aee72aaa5c8 --- /dev/null +++ b/slideshow/source/engine/slide/slideimpl.cxx @@ -0,0 +1,1215 @@ +/************************************************************************* + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: slideimpl.cxx,v $ + * + * $Revision: 1.2 $ + * + * last change: $Author: obo $ $Date: 2007-07-17 14:57:53 $ + * + * The Contents of this file are made available subject to + * the terms of GNU Lesser General Public License Version 2.1. + * + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2005 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_slideshow.hxx" + +#include <osl/diagnose.hxx> +#include <canvas/debug.hxx> +#include <canvas/canvastools.hxx> +#include <cppcanvas/basegfxfactory.hxx> + +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/numeric/ftools.hxx> + +#include <com/sun/star/awt/SystemPointer.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/drawing/XMasterPageTarget.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/presentation/EffectNodeType.hpp> +#include <com/sun/star/animations/XAnimationNodeSupplier.hpp> +#include <com/sun/star/animations/XTargetPropertiesCreator.hpp> +#include <com/sun/star/drawing/TextAnimationKind.hpp> + +#include <animations/animationnodehelper.hxx> + +#include <cppuhelper/exc_hlp.hxx> +#include <comphelper/anytostring.hxx> + +#include "slide.hxx" +#include "slideshowcontext.hxx" +#include "slideanimations.hxx" +#include "doctreenode.hxx" +#include "screenupdater.hxx" +#include "cursormanager.hxx" +#include "shapeimporter.hxx" +#include "slideshowexceptions.hxx" +#include "eventqueue.hxx" +#include "activitiesqueue.hxx" +#include "layermanager.hxx" +#include "shapemanagerimpl.hxx" +#include "usereventqueue.hxx" +#include "userpaintoverlay.hxx" +#include "event.hxx" +#include "tools.hxx" + +#include <boost/bind.hpp> +#include <iterator> +#include <algorithm> +#include <functional> + + +using namespace ::com::sun::star; + +// ----------------------------------------------------------------------------- + +namespace slideshow +{ +namespace internal +{ +namespace +{ + +class SlideImpl : public Slide, + public CursorManager, + public ViewEventHandler, + protected ::osl::DebugBase<SlideImpl> +{ +public: + SlideImpl( const uno::Reference<drawing::XDrawPage>& xDrawPage, + const uno::Reference<animations::XAnimationNode>& xRootNode, + EventQueue& rEventQueue, + EventMultiplexer& rEventMultiplexer, + ScreenUpdater& rScreenUpdater, + ActivitiesQueue& rActivitiesQueue, + UserEventQueue& rUserEventQueue, + CursorManager& rCursorManager, + const UnoViewContainer& rViewContainer, + const uno::Reference<uno::XComponentContext>& xContext, + const ShapeEventListenerMap& rShapeListenerMap, + const ShapeCursorMap& rShapeCursorMap, + RGBColor const& rUserPaintColor, + bool bUserPaintEnabled, + bool bIntrinsicAnimationsAllowed, + bool bDisableAnimationZOrder ); + + ~SlideImpl(); + + + // Disposable interface + // ------------------------------------------------------------------- + + virtual void dispose(); + + + // Slide interface + // ------------------------------------------------------------------- + + virtual bool prefetch(); + virtual bool show( bool ); + virtual void hide(); + + virtual basegfx::B2ISize getSlideSize() const; + virtual uno::Reference<drawing::XDrawPage > getXDrawPage() const; + virtual uno::Reference<animations::XAnimationNode> getXAnimationNode() const; + + // TODO(F2): Rework SlideBitmap to no longer be based on XBitmap, + // but on canvas-independent basegfx bitmaps + virtual SlideBitmapSharedPtr getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const; + + +private: + // ViewEventHandler + virtual void viewAdded( const UnoViewSharedPtr& rView ); + virtual void viewRemoved( const UnoViewSharedPtr& rView ); + virtual void viewChanged( const UnoViewSharedPtr& rView ); + virtual void viewsChanged(); + + // CursorManager + virtual bool requestCursor( sal_Int16 nCursorShape ); + virtual void resetCursor(); + + /** Query whether the slide has animations at all + + If the slide doesn't have animations, show() displays + only static content. If an event is registered with + registerSlideEndEvent(), this event will be + immediately activated at the end of the show() method. + + @return true, if this slide has animations, false + otherwise + */ + bool isAnimated(); + + /** Query whether this slide is currently showing. + + @return true, if this slide is currently showing. + */ + bool isShowing() const; + + void enablePaintOverlay(); + void disablePaintOverlay(); + + /// Set all Shapes to their initial attributes for slideshow + bool applyInitialShapeAttributes( const ::com::sun::star::uno::Reference< + ::com::sun::star::animations::XAnimationNode >& xRootAnimationNode ); + + /// Renders current slide content to bitmap + SlideBitmapSharedPtr createCurrentSlideBitmap( + const UnoViewSharedPtr& rView, + ::basegfx::B2ISize const & rSlideSize ) const; + + /// Prefetch all shapes (not the animations) + bool loadShapes(); + + /// Retrieve slide size from XDrawPage + basegfx::B2ISize getSlideSizeImpl() const; + + /// Prefetch show, but don't call applyInitialShapeAttributes() + bool implPrefetchShow(); + + /// Query the rectangle covered by the slide + ::basegfx::B2DRectangle getSlideRect() const; + + /// Start GIF and other intrinsic shape animations + void endIntrinsicAnimations(); + + /// End GIF and other intrinsic shape animations + void startIntrinsicAnimations(); + + + // Types + // ===== + + enum SlideAnimationState + { + CONSTRUCTING_STATE=0, + INITIAL_STATE=1, + SHOWING_STATE=2, + FINAL_STATE=3, + SlideAnimationState_NUM_ENTRIES=4 + }; + + typedef std::vector< SlideBitmapSharedPtr > VectorOfSlideBitmaps; + /** Vector of slide bitmaps. + + Since the bitmap content is sensitive to animation + effects, we have an inner vector containing a distinct + bitmap for each of the SlideAnimationStates. + */ + typedef ::std::vector< std::pair< UnoViewSharedPtr, + VectorOfSlideBitmaps > > VectorOfVectorOfSlideBitmaps; + + + // Member variables + // ================ + + /// The page model object + uno::Reference< drawing::XDrawPage > mxDrawPage; + uno::Reference< animations::XAnimationNode > mxRootNode; + + LayerManagerSharedPtr mpLayerManager; + boost::shared_ptr<ShapeManagerImpl> mpShapeManager; + boost::shared_ptr<SubsettableShapeManager> mpSubsettableShapeManager; + + /// Contains common objects needed throughout the slideshow + SlideShowContext maContext; + + /// parent cursor manager + CursorManager& mrCursorManager; + + /// Handles the animation and event generation for us + SlideAnimations maAnimations; + + RGBColor maUserPaintColor; + UserPaintOverlaySharedPtr mpPaintOverlay; + + /// Bitmaps with slide content at various states + mutable VectorOfVectorOfSlideBitmaps maSlideBitmaps; + + SlideAnimationState meAnimationState; + + const basegfx::B2ISize maSlideSize; + + sal_Int16 mnCurrentCursor; + + /// True, when intrinsic shape animations are allowed + bool mbIntrinsicAnimationsAllowed; + + /// True, when user paint overlay is enabled + bool mbUserPaintOverlayEnabled; + + /// True, if initial load of all page shapes succeeded + bool mbShapesLoaded; + + /// True, if initial load of all animation info succeeded + bool mbShowLoaded; + + /** True, if this slide is not static. + + If this slide has animated content, this variable will + be true, and false otherwise. + */ + bool mbHaveAnimations; + + /** True, if this slide has a main animation sequence. + + If this slide has animation content, which in turn has + a main animation sequence (which must be fully run + before EventMultiplexer::notifySlideAnimationsEnd() is + called), this member is true. + */ + bool mbMainSequenceFound; + + /// When true, show() was called. Slide hidden oherwise. + bool mbActive; +}; + + +////////////////////////////////////////////////////////////////////////////////// + + +class SlideRenderer +{ +public: + explicit SlideRenderer( SlideImpl& rSlide ) : + mrSlide( rSlide ) + { + } + + void operator()( const UnoViewSharedPtr& rView ) + { + // fully clear view content to background color + rView->clearAll(); + + SlideBitmapSharedPtr pBitmap( mrSlide.getCurrentSlideBitmap( rView ) ); + ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() ); + + const ::basegfx::B2DHomMatrix aViewTransform( rView->getTransformation() ); + const ::basegfx::B2DPoint aOutPosPixel( aViewTransform * ::basegfx::B2DPoint() ); + + // setup a canvas with device coordinate space, the slide + // bitmap already has the correct dimension. + ::cppcanvas::CanvasSharedPtr pDevicePixelCanvas( pCanvas->clone() ); + pDevicePixelCanvas->setTransformation( ::basegfx::B2DHomMatrix() ); + + // render at given output position + pBitmap->move( aOutPosPixel ); + + // clear clip (might have been changed, e.g. from comb + // transition) + pBitmap->clip( ::basegfx::B2DPolyPolygon() ); + pBitmap->draw( pDevicePixelCanvas ); + } + +private: + SlideImpl& mrSlide; +}; + + +////////////////////////////////////////////////////////////////////////////////// + + +SlideImpl::SlideImpl( const uno::Reference< drawing::XDrawPage >& xDrawPage, + const uno::Reference< animations::XAnimationNode >& xRootNode, + EventQueue& rEventQueue, + EventMultiplexer& rEventMultiplexer, + ScreenUpdater& rScreenUpdater, + ActivitiesQueue& rActivitiesQueue, + UserEventQueue& rUserEventQueue, + CursorManager& rCursorManager, + const UnoViewContainer& rViewContainer, + const uno::Reference< uno::XComponentContext >& xComponentContext, + const ShapeEventListenerMap& rShapeListenerMap, + const ShapeCursorMap& rShapeCursorMap, + RGBColor const& aUserPaintColor, + bool bUserPaintEnabled, + bool bIntrinsicAnimationsAllowed, + bool bDisableAnimationZOrder ) : + mxDrawPage( xDrawPage ), + mxRootNode( xRootNode ), + mpLayerManager( new LayerManager( + rViewContainer, + getSlideRect(), + bDisableAnimationZOrder) ), + mpShapeManager( new ShapeManagerImpl( + rEventMultiplexer, + mpLayerManager, + rCursorManager, + rShapeListenerMap, + rShapeCursorMap)), + mpSubsettableShapeManager( mpShapeManager ), + maContext( mpSubsettableShapeManager, + rEventQueue, + rEventMultiplexer, + rScreenUpdater, + rActivitiesQueue, + rUserEventQueue, + *this, + rViewContainer, + xComponentContext ), + mrCursorManager( rCursorManager ), + maAnimations( maContext, + getSlideSizeImpl() ), + maUserPaintColor(aUserPaintColor), + mpPaintOverlay(), + maSlideBitmaps(), + meAnimationState( CONSTRUCTING_STATE ), + maSlideSize(getSlideSizeImpl()), + mnCurrentCursor( awt::SystemPointer::ARROW ), + mbIntrinsicAnimationsAllowed( bIntrinsicAnimationsAllowed ), + mbUserPaintOverlayEnabled(bUserPaintEnabled), + mbShapesLoaded( false ), + mbShowLoaded( false ), + mbHaveAnimations( false ), + mbMainSequenceFound( false ), + mbActive( false ) +{ + // clone already existing views for slide bitmaps + std::for_each( rViewContainer.begin(), + rViewContainer.end(), + boost::bind( &SlideImpl::viewAdded, + this, + _1 )); + + // register screen update (LayerManager needs to signal pending + // updates) + maContext.mrScreenUpdater.addViewUpdate(mpShapeManager); +} + +SlideImpl::~SlideImpl() +{ + if( mpShapeManager ) + { + maContext.mrScreenUpdater.removeViewUpdate(mpShapeManager); + mpShapeManager->dispose(); + + // TODO(Q3): Make sure LayerManager (and thus Shapes) dies + // first, because SlideShowContext has SubsettableShapeManager + // as reference member. + mpLayerManager.reset(); + } +} + +void SlideImpl::dispose() +{ + maSlideBitmaps.clear(); + mpPaintOverlay.reset(); + maAnimations.dispose(); + maContext.dispose(); + + if( mpShapeManager ) + { + maContext.mrScreenUpdater.removeViewUpdate(mpShapeManager); + mpShapeManager->dispose(); + } + + // TODO(Q3): Make sure LayerManager (and thus Shapes) dies first, + // because SlideShowContext has SubsettableShapeManager as + // reference member. + mpLayerManager.reset(); + mpSubsettableShapeManager.reset(); + mpShapeManager.reset(); + mxRootNode.clear(); + mxDrawPage.clear(); +} + +bool SlideImpl::prefetch() +{ + if( !mxRootNode.is() ) + return false; + + return applyInitialShapeAttributes(mxRootNode); +} + +bool SlideImpl::show( bool bSlideBackgoundPainted ) +{ + // --------------------------------------------------------------- + + if( mbActive ) + return true; // already active + + if( !mpShapeManager || !mpLayerManager ) + return false; // disposed + + // --------------------------------------------------------------- + + // set initial shape attributes (e.g. hide shapes that have + // 'appear' effect set) + if( !applyInitialShapeAttributes(mxRootNode) ) + return false; + + // --------------------------------------------------------------- + + // activate and take over view - clears view, if necessary + mbActive = true; + requestCursor( mnCurrentCursor ); + + // enable shape management & event broadcasting for shapes of this + // slide. Also enables LayerManager to record updates. Currently, + // never let LayerManager render initial slide content, use + // buffered slide bitmaps instead. + mpShapeManager->activate( true ); + + // --------------------------------------------------------------- + + // render slide to screen, if requested + if( !bSlideBackgoundPainted ) + { + std::for_each(maContext.mrViewContainer.begin(), + maContext.mrViewContainer.end(), + boost::mem_fn(&View::clearAll)); + + std::for_each( maContext.mrViewContainer.begin(), + maContext.mrViewContainer.end(), + SlideRenderer(*this) ); + maContext.mrScreenUpdater.notifyUpdate(); + } + + // --------------------------------------------------------------- + + // fire up animations + const bool bIsAnimated( isAnimated() ); + if( bIsAnimated ) + maAnimations.start(); // feeds initial events into queue + + // NOTE: this looks slightly weird, but is indeed correct: + // as isAnimated() might return false, _although_ there is + // a main sequence (because the animation nodes don't + // contain any executable effects), we gotta check both + // conditions here. + if( !bIsAnimated || !mbMainSequenceFound ) + { + // manually trigger a slide animation end event (we don't have + // animations at all, or we don't have a main animation + // sequence, but if we had, it'd end now). Note that having + // animations alone does not matter here, as only main + // sequence animations prevents showing the next slide on + // nextEvent(). + maContext.mrEventMultiplexer.notifySlideAnimationsEnd(); + } + + // enable shape-intrinsic animations (drawing layer animations or + // GIF animations) + if( mbIntrinsicAnimationsAllowed ) + startIntrinsicAnimations(); + + // --------------------------------------------------------------- + + // enable paint overlay, if maUserPaintColor is valid + enablePaintOverlay(); + + // --------------------------------------------------------------- + + // from now on, animations might be showing + meAnimationState = SHOWING_STATE; + + return true; +} + +void SlideImpl::hide() +{ + if( !mbActive || !mpShapeManager ) + return; // already hidden/disposed + + // --------------------------------------------------------------- + + // from now on, all animations are stopped + meAnimationState = FINAL_STATE; + + // --------------------------------------------------------------- + + // disable user paint overlay under all circumstances, + // this slide now ceases to be active. + disablePaintOverlay(); + + // --------------------------------------------------------------- + + // switch off all shape-intrinsic animations. + endIntrinsicAnimations(); + + // force-end all SMIL animations, too + maAnimations.end(); + + // --------------------------------------------------------------- + + // disable shape management & event broadcasting for shapes of this + // slide. Also disables LayerManager. + mpShapeManager->deactivate(); + + // vanish from view + resetCursor(); + mbActive = false; + + // --------------------------------------------------------------- +} + +basegfx::B2ISize SlideImpl::getSlideSize() const +{ + return maSlideSize; +} + +uno::Reference<drawing::XDrawPage > SlideImpl::getXDrawPage() const +{ + return mxDrawPage; +} + +uno::Reference<animations::XAnimationNode> SlideImpl::getXAnimationNode() const +{ + return mxRootNode; +} + + +SlideBitmapSharedPtr SlideImpl::getCurrentSlideBitmap( const UnoViewSharedPtr& rView ) const +{ + // search corresponding entry in maSlideBitmaps (which + // contains the views as the key) + VectorOfVectorOfSlideBitmaps::iterator aIter; + const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() ); + if( (aIter=std::find_if( maSlideBitmaps.begin(), + aEnd, + boost::bind( + std::equal_to<UnoViewSharedPtr>(), + rView, + // select view: + boost::bind( + std::select1st<VectorOfVectorOfSlideBitmaps::value_type>(), + _1 )))) == aEnd ) + { + // corresponding view not found - maybe view was not + // added to Slide? + ENSURE_AND_THROW( false, + "SlideImpl::getInitialSlideBitmap(): view does not " + "match any of the added ones" ); + } + + // ensure that the show is loaded + if( !mbShowLoaded ) + { + // only prefetch and init shapes when not done already + // (otherwise, at least applyInitialShapeAttributes() will be + // called twice for initial slide rendering). Furthermore, + // applyInitialShapeAttributes() _always_ performs + // initializations, which would be highly unwanted during a + // running show. OTOH, a slide whose mbShowLoaded is false is + // guaranteed not be running a show. + + // set initial shape attributes (e.g. hide 'appear' effect + // shapes) + if( !const_cast<SlideImpl*>(this)->applyInitialShapeAttributes( mxRootNode ) ) + ENSURE_AND_THROW(false, + "SlideImpl::getCurrentSlideBitmap(): Cannot " + "apply initial attributes"); + } + + SlideBitmapSharedPtr& rBitmap( aIter->second.at( meAnimationState )); + const ::basegfx::B2ISize& rSlideSize( + getSlideSizePixel( getSlideSize(), + rView )); + + // is the bitmap valid (actually existent, and of correct + // size)? + if( !rBitmap || rBitmap->getSize() != rSlideSize ) + { + // no bitmap there yet, or wrong size - create one + rBitmap = createCurrentSlideBitmap(rView, rSlideSize); + } + + return rBitmap; +} + + +// private methods +//-------------------------------------------------------------------------------------------------------------- + + +void SlideImpl::viewAdded( const UnoViewSharedPtr& rView ) +{ + maSlideBitmaps.push_back( + std::make_pair( rView, + VectorOfSlideBitmaps(SlideAnimationState_NUM_ENTRIES) )); + + if( mpLayerManager ) + mpLayerManager->viewAdded( rView ); +} + +void SlideImpl::viewRemoved( const UnoViewSharedPtr& rView ) +{ + if( mpLayerManager ) + mpLayerManager->viewRemoved( rView ); + + const VectorOfVectorOfSlideBitmaps::iterator aEnd( maSlideBitmaps.end() ); + maSlideBitmaps.erase( + std::remove_if( maSlideBitmaps.begin(), + aEnd, + boost::bind( + std::equal_to<UnoViewSharedPtr>(), + rView, + // select view: + boost::bind( + std::select1st<VectorOfVectorOfSlideBitmaps::value_type>(), + _1 ))), + aEnd ); +} + +void SlideImpl::viewChanged( const UnoViewSharedPtr& rView ) +{ + // nothing to do for the Slide - getCurrentSlideBitmap() lazily + // handles bitmap resizes + if( mbActive && mpLayerManager ) + mpLayerManager->viewChanged(rView); +} + +void SlideImpl::viewsChanged() +{ + // nothing to do for the Slide - getCurrentSlideBitmap() lazily + // handles bitmap resizes + if( mbActive && mpLayerManager ) + mpLayerManager->viewsChanged(); +} + +bool SlideImpl::requestCursor( sal_Int16 nCursorShape ) +{ + mnCurrentCursor = nCursorShape; + return mrCursorManager.requestCursor(mnCurrentCursor); +} + +void SlideImpl::resetCursor() +{ + mnCurrentCursor = awt::SystemPointer::ARROW; + mrCursorManager.resetCursor(); +} + +bool SlideImpl::isShowing() const +{ + return meAnimationState == SHOWING_STATE; +} + +bool SlideImpl::isAnimated() +{ + // prefetch, but don't apply initial shape attributes + if( !implPrefetchShow() ) + return false; + + return mbHaveAnimations && maAnimations.isAnimated(); +} + +SlideBitmapSharedPtr SlideImpl::createCurrentSlideBitmap( const UnoViewSharedPtr& rView, + const ::basegfx::B2ISize& rBmpSize ) const +{ + ENSURE_AND_THROW( rView && rView->getCanvas(), + "SlideImpl::createCurrentSlideBitmap(): Invalid view" ); + ENSURE_AND_THROW( mpLayerManager, + "SlideImpl::createCurrentSlideBitmap(): Invalid layer manager" ); + ENSURE_AND_THROW( mbShowLoaded, + "SlideImpl::createCurrentSlideBitmap(): No show loaded" ); + + ::cppcanvas::CanvasSharedPtr pCanvas( rView->getCanvas() ); + + // create a bitmap of appropriate size + ::cppcanvas::BitmapSharedPtr pBitmap( + ::cppcanvas::BaseGfxFactory::getInstance().createBitmap( + pCanvas, + rBmpSize ) ); + + ENSURE_AND_THROW( pBitmap, + "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap" ); + + ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( pBitmap->getBitmapCanvas() ); + + ENSURE_AND_THROW( pBitmapCanvas, + "SlideImpl::createCurrentSlideBitmap(): Cannot create page bitmap canvas" ); + + // apply linear part of destination canvas transformation (linear means in this context: + // transformation without any translational components) + ::basegfx::B2DHomMatrix aLinearTransform( rView->getTransformation() ); + aLinearTransform.set( 0, 2, 0.0 ); + aLinearTransform.set( 1, 2, 0.0 ); + pBitmapCanvas->setTransformation( aLinearTransform ); + + // output all shapes to bitmap + initSlideBackground( pBitmapCanvas, rBmpSize ); + mpLayerManager->renderTo( pBitmapCanvas ); + + return SlideBitmapSharedPtr( new SlideBitmap( pBitmap ) ); +} + +namespace +{ + class MainSequenceSearcher + { + public: + MainSequenceSearcher() + { + maSearchKey.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ); + maSearchKey.Value <<= presentation::EffectNodeType::MAIN_SEQUENCE; + } + + void operator()( const uno::Reference< animations::XAnimationNode >& xChildNode ) + { + uno::Sequence< beans::NamedValue > aUserData( xChildNode->getUserData() ); + + if( findNamedValue( aUserData, maSearchKey ) ) + { + maMainSequence = xChildNode; + } + } + + uno::Reference< animations::XAnimationNode > getMainSequence() const + { + return maMainSequence; + } + + private: + beans::NamedValue maSearchKey; + uno::Reference< animations::XAnimationNode > maMainSequence; + }; +} + +bool SlideImpl::implPrefetchShow() +{ + if( mbShowLoaded ) + return true; + + ENSURE_AND_RETURN( mxDrawPage.is(), + "SlideImpl::implPrefetchShow(): Invalid draw page" ); + ENSURE_AND_RETURN( mpLayerManager, + "SlideImpl::implPrefetchShow(): Invalid layer manager" ); + + // fetch desired page content + // ========================== + + if( !loadShapes() ) + return false; + + // New animations framework: import the shape effect info + // ====================================================== + + try + { + if( mxRootNode.is() ) + { + if( !maAnimations.importAnimations( mxRootNode ) ) + { + OSL_ENSURE( false, + "SlideImpl::implPrefetchShow(): have animation nodes, " + "but import animations failed." ); + + // could not import animation framework, + // _although_ some animation nodes are there - + // this is an error (not finding animations at + // all is okay - might be a static slide) + return false; + } + + // now check whether we've got a main sequence (if + // not, we must manually call + // EventMultiplexer::notifySlideAnimationsEnd() + // above, as e.g. interactive sequences alone + // don't block nextEvent() from issuing the next + // slide) + MainSequenceSearcher aSearcher; + if( ::anim::for_each_childNode( mxRootNode, aSearcher ) ) + mbMainSequenceFound = aSearcher.getMainSequence().is(); + + // import successfully done + mbHaveAnimations = true; + } + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( uno::Exception& ) + { + OSL_ENSURE( + false, + rtl::OUStringToOString( + comphelper::anyToString(cppu::getCaughtException()), + RTL_TEXTENCODING_UTF8 ) ); + // TODO(E2): Error handling. For now, bail out + } + + mbShowLoaded = true; + + return true; +} + +void SlideImpl::enablePaintOverlay() +{ + if( mbUserPaintOverlayEnabled ) + mpPaintOverlay = UserPaintOverlay::create( maUserPaintColor, + 2.0, + maContext ); +} + +void SlideImpl::disablePaintOverlay() +{ + mpPaintOverlay.reset(); +} + +::basegfx::B2DRectangle SlideImpl::getSlideRect() const +{ + const basegfx::B2ISize slideSize( getSlideSizeImpl() ); + return ::basegfx::B2DRectangle(0.0,0.0, + slideSize.getX(), + slideSize.getY()); +} + +void SlideImpl::endIntrinsicAnimations() +{ + mpSubsettableShapeManager->notifyIntrinsicAnimationsDisabled(); +} + +void SlideImpl::startIntrinsicAnimations() +{ + mpSubsettableShapeManager->notifyIntrinsicAnimationsEnabled(); +} + +bool SlideImpl::applyInitialShapeAttributes( + const uno::Reference< animations::XAnimationNode >& xRootAnimationNode ) +{ + if( !implPrefetchShow() ) + return false; + + if( !xRootAnimationNode.is() ) + { + meAnimationState = INITIAL_STATE; + + return true; // no animations - no attributes to apply - + // succeeded + } + + uno::Reference< animations::XTargetPropertiesCreator > xPropsCreator; + + try + { + ENSURE_AND_RETURN( maContext.mxComponentContext.is(), + "SlideImpl::applyInitialShapeAttributes(): Invalid component context" ); + + uno::Reference<lang::XMultiComponentFactory> xFac( + maContext.mxComponentContext->getServiceManager() ); + + xPropsCreator.set( + xFac->createInstanceWithContext( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.animations.TargetPropertiesCreator") ), + maContext.mxComponentContext ), + uno::UNO_QUERY_THROW ); + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( uno::Exception& ) + { + OSL_ENSURE( + false, + rtl::OUStringToOString( + comphelper::anyToString(cppu::getCaughtException()), + RTL_TEXTENCODING_UTF8 ) ); + + // could not determine initial shape attributes - this + // is an error, as some effects might then be plainly + // invisible + ENSURE_AND_RETURN( false, + "SlideImpl::applyInitialShapeAttributes(): " + "couldn't create TargetPropertiesCreator." ); + } + + uno::Sequence< animations::TargetProperties > aProps( + xPropsCreator->createInitialTargetProperties( xRootAnimationNode ) ); + + // apply extracted values to our shapes + const ::std::size_t nSize( aProps.getLength() ); + for( ::std::size_t i=0; i<nSize; ++i ) + { + sal_Int16 nParaIndex( -1 ); + uno::Reference< drawing::XShape > xShape( aProps[i].Target, + uno::UNO_QUERY ); + + if( !xShape.is() ) + { + // not a shape target. Maybe a ParagraphTarget? + presentation::ParagraphTarget aParaTarget; + + if( (aProps[i].Target >>= aParaTarget) ) + { + // yep, ParagraphTarget found - extract shape + // and index + xShape = aParaTarget.Shape; + nParaIndex = aParaTarget.Paragraph; + } + } + + if( xShape.is() ) + { + ShapeSharedPtr pShape( mpLayerManager->lookupShape( xShape ) ); + + if( !pShape ) + { + OSL_ENSURE( false, + "SlideImpl::applyInitialShapeAttributes(): no shape found for given target" ); + continue; + } + + AttributableShapeSharedPtr pAttrShape( + ::boost::dynamic_pointer_cast< AttributableShape >( pShape ) ); + + if( !pAttrShape ) + { + OSL_ENSURE( false, + "SlideImpl::applyInitialShapeAttributes(): shape found does not " + "implement AttributableShape interface" ); + continue; + } + + if( nParaIndex != -1 ) + { + // our target is a paragraph subset, thus look + // this up first. + const DocTreeNodeSupplier& rNodeSupplier( pAttrShape->getTreeNodeSupplier() ); + + pAttrShape = pAttrShape->getSubset( + rNodeSupplier.getTreeNode( + nParaIndex, + DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) ); + + if( !pAttrShape ) + { + OSL_ENSURE( false, + "SlideImpl::applyInitialShapeAttributes(): shape found does not " + "provide a subset for requested paragraph index" ); + continue; + } + } + + const uno::Sequence< beans::NamedValue >& rShapeProps( aProps[i].Properties ); + const ::std::size_t nShapePropSize( rShapeProps.getLength() ); + for( ::std::size_t j=0; j<nShapePropSize; ++j ) + { + bool bVisible=false; + if( rShapeProps[j].Name.equalsIgnoreAsciiCaseAscii("visibility") && + extractValue( bVisible, + rShapeProps[j].Value, + pShape, + getSlideSize() )) + { + pAttrShape->setVisibility( bVisible ); + } + else + { + OSL_ENSURE( false, + "SlideImpl::applyInitialShapeAttributes(): Unexpected " + "(and unimplemented) property encountered" ); + } + } + } + } + + meAnimationState = INITIAL_STATE; + + return true; +} + +bool SlideImpl::loadShapes() +{ + if( mbShapesLoaded ) + return true; + + ENSURE_AND_RETURN( mxDrawPage.is(), + "SlideImpl::loadShapes(): Invalid draw page" ); + ENSURE_AND_RETURN( mpLayerManager, + "SlideImpl::loadShapes(): Invalid layer manager" ); + + // fetch desired page content + // ========================== + + // also take master page content + uno::Reference< drawing::XDrawPage > xMasterPage; + uno::Reference< drawing::XShapes > xMasterPageShapes; + sal_Int32 nCurrCount(0); + + uno::Reference< drawing::XMasterPageTarget > xMasterPageTarget( mxDrawPage, + uno::UNO_QUERY ); + if( xMasterPageTarget.is() ) + { + xMasterPage = xMasterPageTarget->getMasterPage(); + xMasterPageShapes.set( xMasterPage, + uno::UNO_QUERY ); + + if( xMasterPage.is() && xMasterPageShapes.is() ) + { + // TODO(P2): maybe cache master pages here (or treat the + // masterpage as a single metafile. At least currently, + // masterpages do not contain animation effects) + try + { + // load the masterpage shapes + // ------------------------------------------------------------------------- + ShapeImporter aMPShapesFunctor( xMasterPage, + mxDrawPage, + maContext, + 0, /* shape num starts at 0 */ + true ); + + mpLayerManager->addShape( + aMPShapesFunctor.importBackgroundShape() ); + + while( !aMPShapesFunctor.isImportDone() ) + { + ShapeSharedPtr const& rShape( + aMPShapesFunctor.importShape() ); + if( rShape ) + mpLayerManager->addShape( rShape ); + } + + nCurrCount = xMasterPageShapes->getCount() + 1; + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( ShapeLoadFailedException& ) + { + // TODO(E2): Error handling. For now, bail out + OSL_ENSURE( false, + "SlideImpl::loadShapes(): caught ShapeLoadFailedException" ); + return false; + + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + return false; + } + } + } + + try + { + // load the normal page shapes + // ------------------------------------------------------------------------- + + ShapeImporter aShapesFunctor( mxDrawPage, + mxDrawPage, + maContext, + nCurrCount, + false ); + + while( !aShapesFunctor.isImportDone() ) + { + ShapeSharedPtr const& rShape( + aShapesFunctor.importShape() ); + if( rShape ) + mpLayerManager->addShape( rShape ); + } + } + catch( uno::RuntimeException& ) + { + throw; + } + catch( ShapeLoadFailedException& ) + { + // TODO(E2): Error handling. For now, bail out + OSL_ENSURE( false, + "SlideImpl::loadShapes(): caught ShapeLoadFailedException" ); + return false; + } + catch( uno::Exception& ) + { + OSL_ENSURE( false, + rtl::OUStringToOString( + comphelper::anyToString( cppu::getCaughtException() ), + RTL_TEXTENCODING_UTF8 ).getStr() ); + + return false; + } + + mbShapesLoaded = true; + + return true; +} + +basegfx::B2ISize SlideImpl::getSlideSizeImpl() const +{ + uno::Reference< beans::XPropertySet > xPropSet( + mxDrawPage, uno::UNO_QUERY_THROW ); + + sal_Int32 nDocWidth = 0; + sal_Int32 nDocHeight = 0; + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Width") ) ) >>= nDocWidth; + xPropSet->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Height") ) ) >>= nDocHeight; + + return basegfx::B2ISize( nDocWidth, nDocHeight ); +} + +} // namespace + + +SlideSharedPtr createSlide( const uno::Reference< drawing::XDrawPage >& xDrawPage, + const uno::Reference< animations::XAnimationNode >& xRootNode, + EventQueue& rEventQueue, + EventMultiplexer& rEventMultiplexer, + ScreenUpdater& rScreenUpdater, + ActivitiesQueue& rActivitiesQueue, + UserEventQueue& rUserEventQueue, + CursorManager& rCursorManager, + const UnoViewContainer& rViewContainer, + const uno::Reference< uno::XComponentContext >& xComponentContext, + const ShapeEventListenerMap& rShapeListenerMap, + const ShapeCursorMap& rShapeCursorMap, + RGBColor const& rUserPaintColor, + bool bUserPaintEnabled, + bool bIntrinsicAnimationsAllowed, + bool bDisableAnimationZOrder ) +{ + boost::shared_ptr<SlideImpl> pRet( new SlideImpl( xDrawPage, xRootNode, rEventQueue, + rEventMultiplexer, rScreenUpdater, + rActivitiesQueue, rUserEventQueue, + rCursorManager, rViewContainer, + xComponentContext, rShapeListenerMap, + rShapeCursorMap, rUserPaintColor, + bUserPaintEnabled, + bIntrinsicAnimationsAllowed, + bDisableAnimationZOrder )); + + rEventMultiplexer.addViewHandler( pRet ); + + return pRet; +} + +} // namespace internal +} // namespace slideshow |