/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2008 by Sun Microsystems, Inc. * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: drawinglayeranimation.cxx,v $ * $Revision: 1.5.10.1 $ * * 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 * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_slideshow.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "activity.hxx" #include "wakeupevent.hxx" #include "eventqueue.hxx" #include "drawshapesubsetting.hxx" #include "drawshape.hxx" #include "shapesubset.hxx" #include "shapeattributelayerholder.hxx" #include "slideshowcontext.hxx" #include "tools.hxx" #include "gdimtftools.hxx" #include "eventmultiplexer.hxx" #include "intrinsicanimationactivity.hxx" #include "intrinsicanimationeventhandler.hxx" #include #include #include #include using namespace com::sun::star; using namespace ::slideshow::internal; namespace { class ScrollTextAnimNode { sal_uInt32 mnDuration; // single duration sal_uInt32 mnRepeat; // 0 -> endless double mfStart; double mfStop; sal_uInt32 mnFrequency; // in ms // forth and back change at mnRepeat%2: bool mbAlternate; public: ScrollTextAnimNode( sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop, sal_uInt32 nFrequency, bool bAlternate) : mnDuration(nDuration), mnRepeat(nRepeat), mfStart(fStart), mfStop(fStop), mnFrequency(nFrequency), mbAlternate(bAlternate) {} sal_uInt32 GetDuration() const { return mnDuration; } sal_uInt32 GetRepeat() const { return mnRepeat; } sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; } double GetStart() const { return mfStart; } double GetStop() const { return mfStop; } sal_uInt32 GetFrequency() const { return mnFrequency; } bool DoAlternate() const { return mbAlternate; } double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const; }; double ScrollTextAnimNode::GetStateAtRelativeTime( sal_uInt32 nRelativeTime) const { // #151174# Avoid division by zero. if( mnDuration == 0 ) return mfStop; if(mnRepeat) { // ending const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration); sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration)); if(DoAlternate() && (nRepeatCount + 1L) % 2L) nFrameTime = mnDuration - nFrameTime; return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration)); } else { // endless sal_uInt32 nFrameTime(nRelativeTime % mnDuration); if(DoAlternate()) { const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration); if((nRepeatCount + 1L) % 2L) nFrameTime = mnDuration - nFrameTime; } return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration)); } } class ActivityImpl : public Activity, public boost::enable_shared_from_this, private boost::noncopyable { public: virtual ~ActivityImpl(); ActivityImpl( SlideShowContext const& rContext, boost::shared_ptr const& pWakeupEvent, boost::shared_ptr const& pDrawShape ); bool enableAnimations(); // Disposable: virtual void dispose(); // Activity: virtual double calcTimeLag() const; virtual bool perform(); virtual bool isActive() const; virtual void dequeued(); virtual void end(); private: void updateShapeAttributes( double fTime, basegfx::B2DRectangle const& parentBounds ); // Access to VisibleWhenSTarted flags sal_Bool IsVisibleWhenStarted() const { return mbVisibleWhenStarted; } sal_Bool IsVisibleWhenStopped() const { return mbVisibleWhenStopped; } // scroll horizontal? if sal_False, scroll is vertical. bool ScrollHorizontal() const { return (drawing::TextAnimationDirection_LEFT == meDirection || drawing::TextAnimationDirection_RIGHT == meDirection); } // Access to StepWidth in logical units sal_uInt32 GetStepWidthLogic() const; // is the animation direction opposite? bool DoScrollForward() const { return (drawing::TextAnimationDirection_RIGHT == meDirection || drawing::TextAnimationDirection_DOWN == meDirection); } // do alternate text directions? bool DoAlternate() const { return mbAlternate; } // do scroll in? bool DoScrollIn() const { return mbScrollIn; } // Scroll helper methods void ImpForceScrollTextAnimNodes(); ScrollTextAnimNode* ImpGetScrollTextAnimNode( sal_uInt32 nTime, sal_uInt32& rRelativeTime ); sal_uInt32 ImpRegisterAgainScrollTextMixerState( sal_uInt32 nTime); // calculate the MixerState value for given time double GetMixerState(sal_uInt32 nTime); //////////////////////////////////////////////////////////////////// SlideShowContext maContext; boost::shared_ptr mpWakeupEvent; boost::weak_ptr mpParentDrawShape; DrawShapeSharedPtr mpDrawShape; ShapeAttributeLayerHolder maShapeAttrLayer; GDIMetaFileSharedPtr mpMetaFile; IntrinsicAnimationEventHandlerSharedPtr mpListener; canvas::tools::ElapsedTime maTimer; double mfRotationAngle; bool mbIsShapeAnimated; bool mbIsDisposed; bool mbIsActive; drawing::TextAnimationKind meAnimKind; // The blink frequency in ms sal_uInt32 mnFrequency; // The repeat count, init to 0L which means endless sal_uInt32 mnRepeat; // Flag to decide if text will be shown when animation has ended bool mbVisibleWhenStopped; bool mbVisibleWhenStarted; // Flag decides if TextScroll alternates. Default is sal_False. bool mbAlternate; // Flag to remember if this is a simple scrollin text bool mbScrollIn; // start time for this animation sal_uInt32 mnStartTime; // The AnimationDirection drawing::TextAnimationDirection meDirection; // Get width per Step. Negative means pixel, positive logical units sal_Int32 mnStepWidth; // The single anim steps std::vector< ScrollTextAnimNode > maVector; // the scroll rectangle Rectangle maScrollRectangleLogic; // the paint rectangle Rectangle maPaintRectangleLogic; }; ////////////////////////////////////////////////////////////////////// class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler, private boost::noncopyable { public: explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) : mrActivity( rActivity ) {} private: virtual bool enableAnimations() { return mrActivity.enableAnimations(); } virtual bool disableAnimations() { mrActivity.end(); return true; } ActivityImpl& mrActivity; }; ////////////////////////////////////////////////////////////////////// double ActivityImpl::GetMixerState( sal_uInt32 nTime ) { if( meAnimKind == drawing::TextAnimationKind_BLINK ) { // from AInfoBlinkText: double fRetval(0.0); sal_Bool bDone(sal_False); const sal_uInt32 nLoopTime(2 * mnFrequency); if(mnRepeat) { const sal_uInt32 nEndTime(mnRepeat * nLoopTime); if(nTime >= nEndTime) { if(mbVisibleWhenStopped) fRetval = 0.0; else fRetval = 1.0; bDone = sal_True; } } if(!bDone) { sal_uInt32 nTimeInLoop(nTime % nLoopTime); fRetval = double(nTimeInLoop) / nLoopTime; } return fRetval; } else { // from AInfoScrollText: double fRetval(0.0); ImpForceScrollTextAnimNodes(); if(!maVector.empty()) { sal_uInt32 nRelativeTime; ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime); if(pNode) { // use node fRetval = pNode->GetStateAtRelativeTime(nRelativeTime); } else { // end of animation, take last entry's end fRetval = maVector[maVector.size() - 1L].GetStop(); } } return fRetval; } } // Access to StepWidth in logical units sal_uInt32 ActivityImpl::GetStepWidthLogic() const { // #i69847# Assuming higher DPI sal_uInt32 const PIXEL_TO_LOGIC = 30; sal_uInt32 nRetval(0L); if(mnStepWidth < 0L) { // is in pixels, convert to logical units nRetval = (-mnStepWidth * PIXEL_TO_LOGIC); } else if(mnStepWidth > 0L) { // is in logical units nRetval = mnStepWidth; } if(0L == nRetval) { // step 1 pixel, canned value // #128389# with very high DPIs like in PDF export, this can // still get zero. for that cases, set a default, too (taken // from ainfoscrolltext.cxx) nRetval = 100L; } return nRetval; } void ActivityImpl::ImpForceScrollTextAnimNodes() { if(maVector.empty()) { // prepare values sal_uInt32 nLoopTime; double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic; double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0; double fZeroRelative, fOneRelative, fInitRelative,fDistanceRelative; if(ScrollHorizontal()) { if(DoAlternate()) { if(maPaintRectangleLogic.GetWidth() > maScrollRectangleLogic.GetWidth()) { fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth(); fOneLogicAlternate = maScrollRectangleLogic.Left(); } else { fZeroLogicAlternate = maScrollRectangleLogic.Left(); fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth(); } } fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth(); fOneLogic = maScrollRectangleLogic.Right(); fInitLogic = maPaintRectangleLogic.Left(); } else { if(DoAlternate()) { if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight()) { fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight(); fOneLogicAlternate = maScrollRectangleLogic.Top(); } else { fZeroLogicAlternate = maScrollRectangleLogic.Top(); fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight(); } } fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight(); fOneLogic = maScrollRectangleLogic.Bottom(); fInitLogic = maPaintRectangleLogic.Top(); } fDistanceLogic = fOneLogic - fZeroLogic; fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic; if(DoAlternate()) { fZeroRelative = (fZeroLogicAlternate - fZeroLogic) / fDistanceLogic; fOneRelative = (fOneLogicAlternate - fZeroLogic) / fDistanceLogic; fDistanceRelative = fOneRelative - fZeroRelative; } else { fZeroRelative = 0.0; fOneRelative = 1.0; fDistanceRelative = 1.0; } if(mnStartTime) { // Start time loop ScrollTextAnimNode aStartNode( mnStartTime, 1L, 0.0, 0.0, mnStartTime, false); maVector.push_back(aStartNode); } if(IsVisibleWhenStarted()) { double fRelativeStartValue, fRelativeEndValue,fRelativeDistance; if(DoScrollForward()) { fRelativeStartValue = fInitRelative; fRelativeEndValue = fOneRelative; fRelativeDistance = fRelativeEndValue - fRelativeStartValue; } else { fRelativeStartValue = fInitRelative; fRelativeEndValue = fZeroRelative; fRelativeDistance = fRelativeStartValue - fRelativeEndValue; } const double fNumberSteps = (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic(); nLoopTime = FRound(fNumberSteps * mnFrequency); // init loop ScrollTextAnimNode aInitNode( nLoopTime, 1L, fRelativeStartValue, fRelativeEndValue, mnFrequency, false); maVector.push_back(aInitNode); } // prepare main loop values { double fRelativeStartValue, fRelativeEndValue, fRelativeDistance; if(DoScrollForward()) { fRelativeStartValue = fZeroRelative; fRelativeEndValue = fOneRelative; fRelativeDistance = fRelativeEndValue - fRelativeStartValue; } else { fRelativeStartValue = fOneRelative; fRelativeEndValue = fZeroRelative; fRelativeDistance = fRelativeStartValue - fRelativeEndValue; } const double fNumberSteps = (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic(); nLoopTime = FRound(fNumberSteps * mnFrequency); if(0L == mnRepeat) { if(!DoScrollIn()) { // endless main loop ScrollTextAnimNode aMainNode( nLoopTime, 0L, fRelativeStartValue, fRelativeEndValue, mnFrequency, DoAlternate()); maVector.push_back(aMainNode); } } else { sal_uInt32 nNumRepeat(mnRepeat); if(DoAlternate() && (nNumRepeat + 1L) % 2L) nNumRepeat += 1L; // ending main loop ScrollTextAnimNode aMainNode( nLoopTime, nNumRepeat, fRelativeStartValue, fRelativeEndValue, mnFrequency, DoAlternate()); maVector.push_back(aMainNode); } } if(IsVisibleWhenStopped()) { double fRelativeStartValue, fRelativeEndValue, fRelativeDistance; if(DoScrollForward()) { fRelativeStartValue = fZeroRelative; fRelativeEndValue = fInitRelative; fRelativeDistance = fRelativeEndValue - fRelativeStartValue; } else { fRelativeStartValue = fOneRelative; fRelativeEndValue = fInitRelative; fRelativeDistance = fRelativeStartValue - fRelativeEndValue; } const double fNumberSteps = (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic(); nLoopTime = FRound(fNumberSteps * mnFrequency); // exit loop ScrollTextAnimNode aExitNode( nLoopTime, 1L, fRelativeStartValue, fRelativeEndValue, mnFrequency, false); maVector.push_back(aExitNode); } } } ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode( sal_uInt32 nTime, sal_uInt32& rRelativeTime ) { ScrollTextAnimNode* pRetval = 0L; ImpForceScrollTextAnimNodes(); if(!maVector.empty()) { rRelativeTime = nTime; for(sal_uInt32 a(0L); !pRetval && a < maVector.size(); a++) { ScrollTextAnimNode & rNode = maVector[a]; if(!rNode.GetRepeat()) { // endless loop, use it pRetval = &rNode; } else if(rNode.GetFullTime() > rRelativeTime) { // ending node pRetval = &rNode; } else { // look at next rRelativeTime -= rNode.GetFullTime(); } } } return pRetval; } sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime) { sal_uInt32 nRetval(0L); ImpForceScrollTextAnimNodes(); if(maVector.size()) { sal_uInt32 nRelativeTime; ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime); if(pNode) { // take register time nRetval = pNode->GetFrequency(); } } else { // #i38135# not initialized, return default nRetval = mnFrequency; } return nRetval; } void ActivityImpl::updateShapeAttributes( double fTime, basegfx::B2DRectangle const& parentBounds ) { OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE ); if( meAnimKind == drawing::TextAnimationKind_NONE ) return; double const fMixerState = GetMixerState( static_cast(fTime * 1000.0) ); if( meAnimKind == drawing::TextAnimationKind_BLINK ) { // show/hide text: maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 ); } else if(mpMetaFile) // scroll mode: { // // keep care: the below code is highly sensible to changes... // // rectangle of the pure text: double const fPaintWidth = maPaintRectangleLogic.GetWidth(); double const fPaintHeight = maPaintRectangleLogic.GetHeight(); // rectangle where the scrolling takes place (-> clipping): double const fScrollWidth = maScrollRectangleLogic.GetWidth(); double const fScrollHeight = maScrollRectangleLogic.GetHeight(); basegfx::B2DPoint pos, clipPos; if(ScrollHorizontal()) { double const fOneEquiv( fScrollWidth ); double const fZeroEquiv( -fPaintWidth ); pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) ); clipPos.setX( -pos.getX() ); clipPos.setY( -pos.getY() ); // #i69844# Compensation for text-wider-than-shape case if( fPaintWidth > fScrollWidth ) pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 ); } else { // scroll vertical: double const fOneEquiv( fScrollHeight ); double const fZeroEquiv( -fPaintHeight ); pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) ); clipPos.setX( -pos.getX() ); clipPos.setY( -pos.getY() ); // #i69844# Compensation for text-higher-than-shape case if( fPaintHeight > fScrollHeight ) pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 ); } basegfx::B2DPolygon clipPoly( basegfx::tools::createPolygonFromRect( basegfx::B2DRectangle( clipPos.getX(), clipPos.getY(), clipPos.getX() + fScrollWidth, clipPos.getY() + fScrollHeight ) ) ); if( !::basegfx::fTools::equalZero( mfRotationAngle )) { maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle ); double const fRotate = (mfRotationAngle * M_PI / 180.0); basegfx::B2DHomMatrix aTransform; // position: aTransform.rotate( fRotate ); pos *= aTransform; } pos += parentBounds.getCenter(); maShapeAttrLayer.get()->setPosition( pos ); maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) ); } } bool ActivityImpl::perform() { if( !isActive() ) return false; ENSURE_OR_RETURN( mpDrawShape, "ActivityImpl::perform(): still active, but NULL draw shape" ); DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape ); if( !pParentDrawShape ) return false; // parent has vanished if( pParentDrawShape->isVisible() ) { if( !mbIsShapeAnimated ) { mpDrawShape->setVisibility(true); // shape may be initially hidden maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape ); maTimer.reset(); mbIsShapeAnimated = true; } // update attributes related to current time: basegfx::B2DRectangle const parentBounds( pParentDrawShape->getBounds() ); const double nCurrTime( maTimer.getElapsedTime() ); updateShapeAttributes( nCurrTime, parentBounds ); const sal_uInt32 nFrequency( ImpRegisterAgainScrollTextMixerState( static_cast(nCurrTime * 1000.0)) ); if(nFrequency) { mpWakeupEvent->start(); mpWakeupEvent->setNextTimeout( std::max(0.1,nFrequency/1000.0) ); maContext.mrEventQueue.addEvent( mpWakeupEvent ); if( mpDrawShape->isContentChanged() ) maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape ); } // else: finished, not need to wake up again. } else { // busy-wait, until parent shape gets visible mpWakeupEvent->start(); mpWakeupEvent->setNextTimeout( 2.0 ); } // don't reinsert, WakeupEvent will perform that after the given timeout: return false; } ActivityImpl::ActivityImpl( SlideShowContext const& rContext, boost::shared_ptr const& pWakeupEvent, boost::shared_ptr const& pParentDrawShape ) : maContext(rContext), mpWakeupEvent(pWakeupEvent), mpParentDrawShape(pParentDrawShape), mpListener( new IntrinsicAnimationListener(*this) ), maTimer(rContext.mrEventQueue.getTimer()), mbIsShapeAnimated(false), mbIsDisposed(false), mbIsActive(true), meAnimKind(drawing::TextAnimationKind_NONE), mnStartTime(0L) { // get doctreenode: sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes( DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ); DocTreeNode scrollTextNode( pParentDrawShape->getTreeNode( 0, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH )); // xxx todo: remove this hack if( nNodes > 1 ) scrollTextNode.setEndIndex( pParentDrawShape->getTreeNode( nNodes - 1, DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ).getEndIndex()); // TODO(Q3): Doing this manually, instead of using // ShapeSubset. This is because of lifetime issues (ShapeSubset // generates circular references to parent shape) mpDrawShape = boost::dynamic_pointer_cast( maContext.mpSubsettableShapeManager->getSubsetShape( pParentDrawShape, scrollTextNode )); mpMetaFile = mpDrawShape->forceScrollTextMetaFile(); // make scroll text invisible for slide transition bitmaps mpDrawShape->setVisibility(false); basegfx::B2DRectangle aScrollRect, aPaintRect; ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect, aPaintRect, mpMetaFile ), "ActivityImpl::ActivityImpl(): Could not extract " "scroll anim rectangles from mtf" ); maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle( aScrollRect ); maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle( aPaintRect ); maShapeAttrLayer.createAttributeLayer(mpDrawShape); uno::Reference const xShape( mpDrawShape->getXShape() ); uno::Reference const xProps( xShape, uno::UNO_QUERY_THROW ); getPropertyValue( meAnimKind, xProps, OUSTR("TextAnimationKind") ); OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE ); mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE); mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE); // adopted from in AInfoBlinkText::ImplInit(): sal_Int16 nRepeat(0); getPropertyValue( nRepeat, xProps, OUSTR("TextAnimationCount") ); mnRepeat = nRepeat; if(mbAlternate) { // force visible when started for scroll-forth-and-back, because // slide has been coming in with visible text in the middle: mbVisibleWhenStarted = true; } else { getPropertyValue( mbVisibleWhenStarted, xProps, OUSTR("TextAnimationStartInside") ); } // set visible when stopped getPropertyValue( mbVisibleWhenStopped, xProps, OUSTR("TextAnimatiogonStopInside") ); // rotation: getPropertyValue( mfRotationAngle, xProps, OUSTR("RotateAngle") ); mfRotationAngle /= -100.0; // (switching direction) // set frequency sal_Int16 nDelay(0); getPropertyValue( nDelay, xProps, OUSTR("TextAnimationDelay") ); // set delay if not automatic mnFrequency = (nDelay ? nDelay : // default: meAnimKind == drawing::TextAnimationKind_BLINK ? 250L : 50L ); // adopted from in AInfoScrollText::ImplInit(): // If it is a simple m_bScrollIn, reset some parameters if( DoScrollIn() ) { // most parameters are set correctly from the dialog logic, but // eg VisisbleWhenStopped is grayed out and needs to be corrected here. mbVisibleWhenStopped = true; mbVisibleWhenStarted = false; mnRepeat = 0L; } // Get animation direction getPropertyValue( meDirection, xProps, OUSTR("TextAnimationDirection") ); // Get step width. Negative means pixel, positive logical units getPropertyValue( mnStepWidth, xProps, OUSTR("TextAnimationAmount") ); maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler( mpListener ); } bool ActivityImpl::enableAnimations() { mbIsActive = true; return maContext.mrActivitiesQueue.addActivity( shared_from_this() ); } ActivityImpl::~ActivityImpl() { } void ActivityImpl::dispose() { if( !mbIsDisposed ) { end(); // only remove subset here, since end() is called on slide end // (and we must not spoil the slide preview bitmap with scroll // text) maShapeAttrLayer.reset(); if( mpDrawShape ) { // TODO(Q3): Doing this manually, instead of using // ShapeSubset. This is because of lifetime issues // (ShapeSubset generates circular references to parent // shape) DrawShapeSharedPtr pParent( mpParentDrawShape.lock() ); if( pParent ) maContext.mpSubsettableShapeManager->revokeSubset( pParent, mpDrawShape ); } mpMetaFile.reset(); mpDrawShape.reset(); mpParentDrawShape.reset(); mpWakeupEvent.reset(); maContext.dispose(); mbIsDisposed = true; maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler( mpListener ); } } double ActivityImpl::calcTimeLag() const { return 0.0; } bool ActivityImpl::isActive() const { return mbIsActive; } void ActivityImpl::dequeued() { // not used here } void ActivityImpl::end() { // not used here mbIsActive = false; if( mbIsShapeAnimated ) { maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape ); mbIsShapeAnimated = false; } } } // anon namespace namespace slideshow { namespace internal { boost::shared_ptr createDrawingLayerAnimActivity( SlideShowContext const& rContext, boost::shared_ptr const& pDrawShape ) { boost::shared_ptr pActivity; try { boost::shared_ptr const pWakeupEvent( new WakeupEvent( rContext.mrEventQueue.getTimer(), rContext.mrActivitiesQueue ) ); pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) ); pWakeupEvent->setActivity( pActivity ); } catch( uno::RuntimeException& ) { throw; } catch( uno::Exception& ) { // translate any error into empty factory product. OSL_ENSURE( false, rtl::OUStringToOString( comphelper::anyToString( cppu::getCaughtException() ), RTL_TEXTENCODING_UTF8 ).getStr() ); } return pActivity; } } // namespace internal } // namespace presentation