/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "drawinglayeranimation.hxx" #include "drawshapesubsetting.hxx" #include "drawshape.hxx" #include #include #include #include #include "gdimtftools.hxx" #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 GetRepeat() const { return mnRepeat; } sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; } 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 { // 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 + 1) % 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 + 1) % 2L) nFrameTime = mnDuration - nFrameTime; } return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration)); } } class ActivityImpl : public Activity { public: ActivityImpl( SlideShowContext const& rContext, std::shared_ptr pWakeupEvent, std::shared_ptr const& pDrawShape ); ActivityImpl(const ActivityImpl&) = delete; ActivityImpl& operator=(const ActivityImpl&) = delete; bool enableAnimations(); // Disposable: virtual void dispose() override; // Activity: virtual double calcTimeLag() const override; virtual bool perform() override; virtual bool isActive() const override; virtual void dequeued() override; virtual void end() override; private: void updateShapeAttributes( double fTime, basegfx::B2DRectangle const& parentBounds ); // 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; std::shared_ptr mpWakeupEvent; std::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 scrolling text bool mbScrollIn; // 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 tools::Rectangle maScrollRectangleLogic; // the paint rectangle tools::Rectangle maPaintRectangleLogic; }; class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler { public: explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) : mrActivity( rActivity ) {} IntrinsicAnimationListener(const IntrinsicAnimationListener&) = delete; IntrinsicAnimationListener& operator=(const IntrinsicAnimationListener&) = delete; private: virtual bool enableAnimations() override { return mrActivity.enableAnimations(); } virtual bool disableAnimations() override { mrActivity.end(); return true; } ActivityImpl& mrActivity; }; double ActivityImpl::GetMixerState( sal_uInt32 nTime ) { if( meAnimKind == drawing::TextAnimationKind_BLINK ) { // from AInfoBlinkText: double fRetval(0.0); bool bDone(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 = 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() - 1].GetStop(); } } return fRetval; } } // Access to StepWidth in logical units sal_uInt32 ActivityImpl::GetStepWidthLogic() const { // #i69847# Assuming higher DPI constexpr sal_uInt32 PIXEL_TO_LOGIC = 30; sal_uInt32 nRetval(0); if(mnStepWidth < 0) { // is in pixels, convert to logical units nRetval = (-mnStepWidth * PIXEL_TO_LOGIC); } else if(mnStepWidth > 0) { // is in logical units nRetval = mnStepWidth; } if(0 == nRetval) { // step 1 pixel, canned value // 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 = 100; } return nRetval; } void ActivityImpl::ImpForceScrollTextAnimNodes() { if(!maVector.empty()) return; // prepare values sal_uInt32 nLoopTime; double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic; double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0; double fZeroRelative, fOneRelative, fInitRelative; 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; } else { fZeroRelative = 0.0; fOneRelative = 1.0; } if(mbVisibleWhenStarted) { 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, 1, 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(0 == mnRepeat) { if(!DoScrollIn()) { // endless main loop ScrollTextAnimNode aMainNode( nLoopTime, 0, fRelativeStartValue, fRelativeEndValue, mnFrequency, DoAlternate()); maVector.push_back(aMainNode); } } else { sal_uInt32 nNumRepeat(mnRepeat); if(DoAlternate() && (nNumRepeat + 1) % 2L) nNumRepeat += 1; // ending main loop ScrollTextAnimNode aMainNode( nLoopTime, nNumRepeat, fRelativeStartValue, fRelativeEndValue, mnFrequency, DoAlternate()); maVector.push_back(aMainNode); } } if(!mbVisibleWhenStopped) return; 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, 1, fRelativeStartValue, fRelativeEndValue, mnFrequency, false); maVector.push_back(aExitNode); } ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode( sal_uInt32 nTime, sal_uInt32& rRelativeTime ) { ScrollTextAnimNode* pRetval = nullptr; ImpForceScrollTextAnimNodes(); if(!maVector.empty()) { rRelativeTime = nTime; for(ScrollTextAnimNode & rNode: maVector) { 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(0); ImpForceScrollTextAnimNodes(); if(!maVector.empty()) { 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::utils::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 = basegfx::deg2rad(mfRotationAngle); 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_FALSE( 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, std::shared_ptr pWakeupEvent, std::shared_ptr const& pParentDrawShape ) : maContext(rContext), mpWakeupEvent(std::move(pWakeupEvent)), mpParentDrawShape(pParentDrawShape), mpListener( std::make_shared(*this) ), maTimer(rContext.mrEventQueue.getTimer()), mfRotationAngle(0.0), mbIsShapeAnimated(false), mbIsDisposed(false), mbIsActive(true), meAnimKind(drawing::TextAnimationKind_NONE), mbVisibleWhenStopped(false), mbVisibleWhenStarted(false), mnStepWidth(0) { // get doctreenode: sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes( DocTreeNode::NodeType::LogicalParagraph ); DocTreeNode scrollTextNode( pParentDrawShape->getTreeNode( 0, DocTreeNode::NodeType::LogicalParagraph )); // xxx todo: remove this hack if( nNodes > 1 ) scrollTextNode.setEndIndex( pParentDrawShape->getTreeNode( nNodes - 1, DocTreeNode::NodeType::LogicalParagraph ).getEndIndex()); // TODO(Q3): Doing this manually, instead of using // ShapeSubset. This is because of lifetime issues (ShapeSubset // generates circular references to parent shape) mpDrawShape = std::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, "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, "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, "TextAnimationStartInside" ); } // set visible when stopped getPropertyValue( mbVisibleWhenStopped, xProps, "TextAnimatiogonStopInside" ); // rotation: getPropertyValue( mfRotationAngle, xProps, "RotateAngle" ); mfRotationAngle /= -100.0; // (switching direction) // set frequency sal_Int16 nDelay(0); getPropertyValue( nDelay, xProps, "TextAnimationDelay" ); // set delay if not automatic mnFrequency = (nDelay ? nDelay : // default: meAnimKind == drawing::TextAnimationKind_BLINK ? 250 : 50 ); // 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 VisibleWhenStopped is grayed out and needs to be corrected here. mbVisibleWhenStopped = true; mbVisibleWhenStarted = false; mnRepeat = 0; } // Get animation direction getPropertyValue( meDirection, xProps, "TextAnimationDirection" ); // Get step width. Negative means pixel, positive logical units getPropertyValue( mnStepWidth, xProps, "TextAnimationAmount" ); maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler( mpListener ); } bool ActivityImpl::enableAnimations() { mbIsActive = true; return maContext.mrActivitiesQueue.addActivity( std::dynamic_pointer_cast(shared_from_this()) ); } void ActivityImpl::dispose() { if( mbIsDisposed ) return; 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::internal { std::shared_ptr createDrawingLayerAnimActivity( SlideShowContext const& rContext, std::shared_ptr const& pDrawShape ) { std::shared_ptr pActivity; try { auto const pWakeupEvent = std::make_shared( rContext.mrEventQueue.getTimer(), rContext.mrActivitiesQueue ); pActivity = std::make_shared( rContext, pWakeupEvent, pDrawShape ); pWakeupEvent->setActivity( pActivity ); } catch( uno::RuntimeException& ) { throw; } catch( uno::Exception& ) { // translate any error into empty factory product. TOOLS_WARN_EXCEPTION( "slideshow", "" ); } return pActivity; } } // namespace presentation /* vim:set shiftwidth=4 softtabstop=4 expandtab: */