Bump version to 6.0-36
[LibreOffice.git] / slideshow / source / engine / shapes / drawinglayeranimation.cxx
blob2a642b1a230dd6989a317dcd25ed23df041564e4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <tools/diagnose_ex.h>
22 #include <tools/helpers.hxx>
23 #include <canvas/elapsedtime.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
26 #include <comphelper/anytostring.hxx>
27 #include <cppuhelper/exc_hlp.hxx>
29 #include <rtl/math.hxx>
30 #include <vcl/metric.hxx>
31 #include <vcl/canvastools.hxx>
32 #include <vcl/metaact.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/drawing/TextAnimationKind.hpp>
35 #include <com/sun/star/drawing/TextAnimationDirection.hpp>
36 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
37 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
38 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
39 #include <com/sun/star/awt/Rectangle.hpp>
41 #include <activity.hxx>
42 #include <wakeupevent.hxx>
43 #include <eventqueue.hxx>
44 #include "drawinglayeranimation.hxx"
45 #include "drawshapesubsetting.hxx"
46 #include "drawshape.hxx"
47 #include <shapesubset.hxx>
48 #include <shapeattributelayerholder.hxx>
49 #include <slideshowcontext.hxx>
50 #include <tools.hxx>
51 #include "gdimtftools.hxx"
52 #include <eventmultiplexer.hxx>
53 #include "intrinsicanimationactivity.hxx"
54 #include <intrinsicanimationeventhandler.hxx>
56 #include <vector>
57 #include <memory>
59 using namespace com::sun::star;
60 using namespace ::slideshow::internal;
62 namespace {
64 class ScrollTextAnimNode
66 sal_uInt32 mnDuration; // single duration
67 sal_uInt32 mnRepeat; // 0 -> endless
68 double mfStart;
69 double mfStop;
70 sal_uInt32 mnFrequency; // in ms
71 // forth and back change at mnRepeat%2:
72 bool mbAlternate;
74 public:
75 ScrollTextAnimNode(
76 sal_uInt32 nDuration, sal_uInt32 nRepeat, double fStart, double fStop,
77 sal_uInt32 nFrequency, bool bAlternate)
78 : mnDuration(nDuration),
79 mnRepeat(nRepeat),
80 mfStart(fStart),
81 mfStop(fStop),
82 mnFrequency(nFrequency),
83 mbAlternate(bAlternate)
86 sal_uInt32 GetRepeat() const { return mnRepeat; }
87 sal_uInt32 GetFullTime() const { return mnDuration * mnRepeat; }
88 double GetStop() const { return mfStop; }
89 sal_uInt32 GetFrequency() const { return mnFrequency; }
90 bool DoAlternate() const { return mbAlternate; }
92 double GetStateAtRelativeTime(sal_uInt32 nRelativeTime) const;
95 double ScrollTextAnimNode::GetStateAtRelativeTime(
96 sal_uInt32 nRelativeTime) const
98 // Avoid division by zero.
99 if( mnDuration == 0 )
100 return mfStop;
102 if(mnRepeat)
104 // ending
105 const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
106 sal_uInt32 nFrameTime(nRelativeTime - (nRepeatCount * mnDuration));
108 if(DoAlternate() && (nRepeatCount + 1) % 2L)
109 nFrameTime = mnDuration - nFrameTime;
111 return mfStart + ((mfStop - mfStart) *
112 (double(nFrameTime) / mnDuration));
114 else
116 // endless
117 sal_uInt32 nFrameTime(nRelativeTime % mnDuration);
119 if(DoAlternate())
121 const sal_uInt32 nRepeatCount(nRelativeTime / mnDuration);
123 if((nRepeatCount + 1) % 2L)
124 nFrameTime = mnDuration - nFrameTime;
127 return mfStart + ((mfStop - mfStart) * (double(nFrameTime) / mnDuration));
131 class ActivityImpl : public Activity
133 public:
134 ActivityImpl(
135 SlideShowContext const& rContext,
136 std::shared_ptr<WakeupEvent> const& pWakeupEvent,
137 std::shared_ptr<DrawShape> const& pDrawShape );
139 ActivityImpl(const ActivityImpl&) = delete;
140 ActivityImpl& operator=(const ActivityImpl&) = delete;
142 bool enableAnimations();
144 // Disposable:
145 virtual void dispose() override;
146 // Activity:
147 virtual double calcTimeLag() const override;
148 virtual bool perform() override;
149 virtual bool isActive() const override;
150 virtual void dequeued() override;
151 virtual void end() override;
153 private:
154 void updateShapeAttributes( double fTime,
155 basegfx::B2DRectangle const& parentBounds );
157 // scroll horizontal? if sal_False, scroll is vertical.
158 bool ScrollHorizontal() const {
159 return (drawing::TextAnimationDirection_LEFT == meDirection ||
160 drawing::TextAnimationDirection_RIGHT == meDirection);
163 // Access to StepWidth in logical units
164 sal_uInt32 GetStepWidthLogic() const;
166 // is the animation direction opposite?
167 bool DoScrollForward() const {
168 return (drawing::TextAnimationDirection_RIGHT == meDirection ||
169 drawing::TextAnimationDirection_DOWN == meDirection);
172 // do alternate text directions?
173 bool DoAlternate() const { return mbAlternate; }
175 // do scroll in?
176 bool DoScrollIn() const { return mbScrollIn; }
178 // Scroll helper methods
179 void ImpForceScrollTextAnimNodes();
180 ScrollTextAnimNode* ImpGetScrollTextAnimNode(
181 sal_uInt32 nTime, sal_uInt32& rRelativeTime );
182 sal_uInt32 ImpRegisterAgainScrollTextMixerState(
183 sal_uInt32 nTime);
185 // calculate the MixerState value for given time
186 double GetMixerState(sal_uInt32 nTime);
189 SlideShowContext maContext;
190 std::shared_ptr<WakeupEvent> mpWakeupEvent;
191 std::weak_ptr<DrawShape> mpParentDrawShape;
192 DrawShapeSharedPtr mpDrawShape;
193 ShapeAttributeLayerHolder maShapeAttrLayer;
194 GDIMetaFileSharedPtr mpMetaFile;
195 IntrinsicAnimationEventHandlerSharedPtr mpListener;
196 canvas::tools::ElapsedTime maTimer;
197 double mfRotationAngle;
198 bool mbIsShapeAnimated;
199 bool mbIsDisposed;
200 bool mbIsActive;
201 drawing::TextAnimationKind meAnimKind;
203 // The blink frequency in ms
204 sal_uInt32 mnFrequency;
206 // The repeat count, init to 0L which means endless
207 sal_uInt32 mnRepeat;
209 // Flag to decide if text will be shown when animation has ended
210 bool mbVisibleWhenStopped;
211 bool mbVisibleWhenStarted;
213 // Flag decides if TextScroll alternates. Default is sal_False.
214 bool mbAlternate;
216 // Flag to remember if this is a simple scrolling text
217 bool mbScrollIn;
219 // The AnimationDirection
220 drawing::TextAnimationDirection meDirection;
222 // Get width per Step. Negative means pixel, positive logical units
223 sal_Int32 mnStepWidth;
225 // The single anim steps
226 std::vector< ScrollTextAnimNode > maVector;
228 // the scroll rectangle
229 tools::Rectangle maScrollRectangleLogic;
231 // the paint rectangle
232 tools::Rectangle maPaintRectangleLogic;
236 class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler
238 public:
239 explicit IntrinsicAnimationListener( ActivityImpl& rActivity ) :
240 mrActivity( rActivity )
243 IntrinsicAnimationListener(const IntrinsicAnimationListener&) = delete;
244 IntrinsicAnimationListener& operator=(const IntrinsicAnimationListener&) = delete;
246 private:
248 virtual bool enableAnimations() override { return mrActivity.enableAnimations(); }
249 virtual bool disableAnimations() override { mrActivity.end(); return true; }
251 ActivityImpl& mrActivity;
255 double ActivityImpl::GetMixerState( sal_uInt32 nTime )
257 if( meAnimKind == drawing::TextAnimationKind_BLINK )
259 // from AInfoBlinkText:
260 double fRetval(0.0);
261 bool bDone(false);
262 const sal_uInt32 nLoopTime(2 * mnFrequency);
264 if(mnRepeat)
266 const sal_uInt32 nEndTime(mnRepeat * nLoopTime);
268 if(nTime >= nEndTime)
270 if(mbVisibleWhenStopped)
271 fRetval = 0.0;
272 else
273 fRetval = 1.0;
275 bDone = true;
279 if(!bDone)
281 sal_uInt32 nTimeInLoop(nTime % nLoopTime);
282 fRetval = double(nTimeInLoop) / nLoopTime;
285 return fRetval;
287 else
289 // from AInfoScrollText:
290 double fRetval(0.0);
291 ImpForceScrollTextAnimNodes();
293 if(!maVector.empty())
295 sal_uInt32 nRelativeTime;
296 ScrollTextAnimNode* pNode =
297 ImpGetScrollTextAnimNode(nTime, nRelativeTime);
299 if(pNode)
301 // use node
302 fRetval = pNode->GetStateAtRelativeTime(nRelativeTime);
304 else
306 // end of animation, take last entry's end
307 fRetval = maVector[maVector.size() - 1].GetStop();
311 return fRetval;
315 // Access to StepWidth in logical units
316 sal_uInt32 ActivityImpl::GetStepWidthLogic() const
318 // #i69847# Assuming higher DPI
319 sal_uInt32 const PIXEL_TO_LOGIC = 30;
321 sal_uInt32 nRetval(0);
323 if(mnStepWidth < 0)
325 // is in pixels, convert to logical units
326 nRetval = (-mnStepWidth * PIXEL_TO_LOGIC);
328 else if(mnStepWidth > 0)
330 // is in logical units
331 nRetval = mnStepWidth;
334 if(0 == nRetval)
336 // step 1 pixel, canned value
338 // with very high DPIs like in PDF export, this can
339 // still get zero. for that cases, set a default, too (taken
340 // from ainfoscrolltext.cxx)
341 nRetval = 100;
344 return nRetval;
347 void ActivityImpl::ImpForceScrollTextAnimNodes()
349 if(maVector.empty())
351 // prepare values
352 sal_uInt32 nLoopTime;
353 double fZeroLogic, fOneLogic, fInitLogic, fDistanceLogic;
354 double fZeroLogicAlternate = 0.0, fOneLogicAlternate = 0.0;
355 double fZeroRelative, fOneRelative, fInitRelative;
357 if(ScrollHorizontal())
359 if(DoAlternate())
361 if(maPaintRectangleLogic.GetWidth() >
362 maScrollRectangleLogic.GetWidth())
364 fZeroLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
365 fOneLogicAlternate = maScrollRectangleLogic.Left();
367 else
369 fZeroLogicAlternate = maScrollRectangleLogic.Left();
370 fOneLogicAlternate = maScrollRectangleLogic.Right() - maPaintRectangleLogic.GetWidth();
374 fZeroLogic = maScrollRectangleLogic.Left() - maPaintRectangleLogic.GetWidth();
375 fOneLogic = maScrollRectangleLogic.Right();
376 fInitLogic = maPaintRectangleLogic.Left();
378 else
380 if(DoAlternate())
382 if(maPaintRectangleLogic.GetHeight() > maScrollRectangleLogic.GetHeight())
384 fZeroLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
385 fOneLogicAlternate = maScrollRectangleLogic.Top();
387 else
389 fZeroLogicAlternate = maScrollRectangleLogic.Top();
390 fOneLogicAlternate = maScrollRectangleLogic.Bottom() - maPaintRectangleLogic.GetHeight();
394 fZeroLogic = maScrollRectangleLogic.Top() - maPaintRectangleLogic.GetHeight();
395 fOneLogic = maScrollRectangleLogic.Bottom();
396 fInitLogic = maPaintRectangleLogic.Top();
399 fDistanceLogic = fOneLogic - fZeroLogic;
400 fInitRelative = (fInitLogic - fZeroLogic) / fDistanceLogic;
402 if(DoAlternate())
404 fZeroRelative =
405 (fZeroLogicAlternate - fZeroLogic) / fDistanceLogic;
406 fOneRelative =
407 (fOneLogicAlternate - fZeroLogic) / fDistanceLogic;
409 else
411 fZeroRelative = 0.0;
412 fOneRelative = 1.0;
415 if(mbVisibleWhenStarted)
417 double fRelativeStartValue, fRelativeEndValue,fRelativeDistance;
419 if(DoScrollForward())
421 fRelativeStartValue = fInitRelative;
422 fRelativeEndValue = fOneRelative;
423 fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
425 else
427 fRelativeStartValue = fInitRelative;
428 fRelativeEndValue = fZeroRelative;
429 fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
432 const double fNumberSteps =
433 (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
434 nLoopTime = FRound(fNumberSteps * mnFrequency);
436 // init loop
437 ScrollTextAnimNode aInitNode(
438 nLoopTime, 1,
439 fRelativeStartValue, fRelativeEndValue,
440 mnFrequency, false);
441 maVector.push_back(aInitNode);
444 // prepare main loop values
446 double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
448 if(DoScrollForward())
450 fRelativeStartValue = fZeroRelative;
451 fRelativeEndValue = fOneRelative;
452 fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
454 else
456 fRelativeStartValue = fOneRelative;
457 fRelativeEndValue = fZeroRelative;
458 fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
461 const double fNumberSteps =
462 (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
463 nLoopTime = FRound(fNumberSteps * mnFrequency);
465 if(0 == mnRepeat)
467 if(!DoScrollIn())
469 // endless main loop
470 ScrollTextAnimNode aMainNode(
471 nLoopTime, 0,
472 fRelativeStartValue, fRelativeEndValue,
473 mnFrequency, DoAlternate());
474 maVector.push_back(aMainNode);
477 else
479 sal_uInt32 nNumRepeat(mnRepeat);
481 if(DoAlternate() && (nNumRepeat + 1) % 2L)
482 nNumRepeat += 1;
484 // ending main loop
485 ScrollTextAnimNode aMainNode(
486 nLoopTime, nNumRepeat,
487 fRelativeStartValue, fRelativeEndValue,
488 mnFrequency, DoAlternate());
489 maVector.push_back(aMainNode);
493 if(mbVisibleWhenStopped)
495 double fRelativeStartValue, fRelativeEndValue, fRelativeDistance;
497 if(DoScrollForward())
499 fRelativeStartValue = fZeroRelative;
500 fRelativeEndValue = fInitRelative;
501 fRelativeDistance = fRelativeEndValue - fRelativeStartValue;
503 else
505 fRelativeStartValue = fOneRelative;
506 fRelativeEndValue = fInitRelative;
507 fRelativeDistance = fRelativeStartValue - fRelativeEndValue;
510 const double fNumberSteps =
511 (fRelativeDistance * fDistanceLogic) / GetStepWidthLogic();
512 nLoopTime = FRound(fNumberSteps * mnFrequency);
514 // exit loop
515 ScrollTextAnimNode aExitNode(
516 nLoopTime, 1,
517 fRelativeStartValue, fRelativeEndValue, mnFrequency, false);
518 maVector.push_back(aExitNode);
523 ScrollTextAnimNode* ActivityImpl::ImpGetScrollTextAnimNode(
524 sal_uInt32 nTime, sal_uInt32& rRelativeTime )
526 ScrollTextAnimNode* pRetval = nullptr;
527 ImpForceScrollTextAnimNodes();
529 if(!maVector.empty())
531 rRelativeTime = nTime;
533 for(ScrollTextAnimNode & rNode: maVector)
535 if(!rNode.GetRepeat())
537 // endless loop, use it
538 pRetval = &rNode;
540 else if(rNode.GetFullTime() > rRelativeTime)
542 // ending node
543 pRetval = &rNode;
545 else
547 // look at next
548 rRelativeTime -= rNode.GetFullTime();
553 return pRetval;
556 sal_uInt32 ActivityImpl::ImpRegisterAgainScrollTextMixerState(sal_uInt32 nTime)
558 sal_uInt32 nRetval(0);
559 ImpForceScrollTextAnimNodes();
561 if(!maVector.empty())
563 sal_uInt32 nRelativeTime;
564 ScrollTextAnimNode* pNode = ImpGetScrollTextAnimNode(nTime, nRelativeTime);
566 if(pNode)
568 // take register time
569 nRetval = pNode->GetFrequency();
572 else
574 // #i38135# not initialized, return default
575 nRetval = mnFrequency;
578 return nRetval;
581 void ActivityImpl::updateShapeAttributes(
582 double fTime, basegfx::B2DRectangle const& parentBounds )
584 OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
585 if( meAnimKind == drawing::TextAnimationKind_NONE )
586 return;
588 double const fMixerState = GetMixerState(
589 static_cast<sal_uInt32>(fTime * 1000.0) );
591 if( meAnimKind == drawing::TextAnimationKind_BLINK )
593 // show/hide text:
594 maShapeAttrLayer.get()->setVisibility( fMixerState < 0.5 );
596 else if(mpMetaFile) // scroll mode:
599 // keep care: the below code is highly sensible to changes...
602 // rectangle of the pure text:
603 double const fPaintWidth = maPaintRectangleLogic.GetWidth();
604 double const fPaintHeight = maPaintRectangleLogic.GetHeight();
605 // rectangle where the scrolling takes place (-> clipping):
606 double const fScrollWidth = maScrollRectangleLogic.GetWidth();
607 double const fScrollHeight = maScrollRectangleLogic.GetHeight();
609 basegfx::B2DPoint pos, clipPos;
611 if(ScrollHorizontal())
613 double const fOneEquiv( fScrollWidth );
614 double const fZeroEquiv( -fPaintWidth );
616 pos.setX( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
618 clipPos.setX( -pos.getX() );
619 clipPos.setY( -pos.getY() );
621 // #i69844# Compensation for text-wider-than-shape case
622 if( fPaintWidth > fScrollWidth )
623 pos.setX( pos.getX() + (fPaintWidth-fScrollWidth) / 2.0 );
625 else
627 // scroll vertical:
628 double const fOneEquiv( fScrollHeight );
629 double const fZeroEquiv( -fPaintHeight );
631 pos.setY( fZeroEquiv + (fMixerState * (fOneEquiv - fZeroEquiv)) );
633 clipPos.setX( -pos.getX() );
634 clipPos.setY( -pos.getY() );
636 // #i69844# Compensation for text-higher-than-shape case
637 if( fPaintHeight > fScrollHeight )
638 pos.setY( pos.getY() + (fPaintHeight-fScrollHeight) / 2.0 );
641 basegfx::B2DPolygon clipPoly(
642 basegfx::utils::createPolygonFromRect(
643 basegfx::B2DRectangle( clipPos.getX(),
644 clipPos.getY(),
645 clipPos.getX() + fScrollWidth,
646 clipPos.getY() + fScrollHeight ) ) );
648 if( !::basegfx::fTools::equalZero( mfRotationAngle ))
650 maShapeAttrLayer.get()->setRotationAngle( mfRotationAngle );
651 double const fRotate = (mfRotationAngle * M_PI / 180.0);
652 basegfx::B2DHomMatrix aTransform;
653 // position:
654 aTransform.rotate( fRotate );
655 pos *= aTransform;
658 pos += parentBounds.getCenter();
659 maShapeAttrLayer.get()->setPosition( pos );
660 maShapeAttrLayer.get()->setClip( basegfx::B2DPolyPolygon(clipPoly) );
664 bool ActivityImpl::perform()
666 if( !isActive() )
667 return false;
669 ENSURE_OR_RETURN_FALSE(
670 mpDrawShape,
671 "ActivityImpl::perform(): still active, but NULL draw shape" );
673 DrawShapeSharedPtr const pParentDrawShape( mpParentDrawShape );
674 if( !pParentDrawShape )
675 return false; // parent has vanished
677 if( pParentDrawShape->isVisible() )
679 if( !mbIsShapeAnimated )
681 mpDrawShape->setVisibility(true); // shape may be initially hidden
682 maContext.mpSubsettableShapeManager->enterAnimationMode( mpDrawShape );
683 maTimer.reset();
684 mbIsShapeAnimated = true;
686 // update attributes related to current time:
687 basegfx::B2DRectangle const parentBounds(
688 pParentDrawShape->getBounds() );
690 const double nCurrTime( maTimer.getElapsedTime() );
691 updateShapeAttributes( nCurrTime, parentBounds );
693 const sal_uInt32 nFrequency(
694 ImpRegisterAgainScrollTextMixerState(
695 static_cast<sal_uInt32>(nCurrTime * 1000.0)) );
697 if(nFrequency)
699 mpWakeupEvent->start();
700 mpWakeupEvent->setNextTimeout(
701 std::max(0.1,nFrequency/1000.0) );
702 maContext.mrEventQueue.addEvent( mpWakeupEvent );
704 if( mpDrawShape->isContentChanged() )
705 maContext.mpSubsettableShapeManager->notifyShapeUpdate( mpDrawShape );
707 // else: finished, not need to wake up again.
709 else
711 // busy-wait, until parent shape gets visible
712 mpWakeupEvent->start();
713 mpWakeupEvent->setNextTimeout( 2.0 );
716 // don't reinsert, WakeupEvent will perform that after the given timeout:
717 return false;
720 ActivityImpl::ActivityImpl(
721 SlideShowContext const& rContext,
722 std::shared_ptr<WakeupEvent> const& pWakeupEvent,
723 std::shared_ptr<DrawShape> const& pParentDrawShape )
724 : maContext(rContext),
725 mpWakeupEvent(pWakeupEvent),
726 mpParentDrawShape(pParentDrawShape),
727 mpListener( new IntrinsicAnimationListener(*this) ),
728 maTimer(rContext.mrEventQueue.getTimer()),
729 mfRotationAngle(0.0),
730 mbIsShapeAnimated(false),
731 mbIsDisposed(false),
732 mbIsActive(true),
733 meAnimKind(drawing::TextAnimationKind_NONE),
734 mbVisibleWhenStopped(false),
735 mbVisibleWhenStarted(false),
736 mnStepWidth(0)
738 // get doctreenode:
739 sal_Int32 const nNodes = pParentDrawShape->getNumberOfTreeNodes(
740 DocTreeNode::NodeType::LogicalParagraph );
742 DocTreeNode scrollTextNode(
743 pParentDrawShape->getTreeNode(
744 0, DocTreeNode::NodeType::LogicalParagraph ));
745 // xxx todo: remove this hack
746 if( nNodes > 1 )
747 scrollTextNode.setEndIndex(
748 pParentDrawShape->getTreeNode(
749 nNodes - 1,
750 DocTreeNode::NodeType::LogicalParagraph ).getEndIndex());
752 // TODO(Q3): Doing this manually, instead of using
753 // ShapeSubset. This is because of lifetime issues (ShapeSubset
754 // generates circular references to parent shape)
755 mpDrawShape = std::dynamic_pointer_cast<DrawShape>(
756 maContext.mpSubsettableShapeManager->getSubsetShape(
757 pParentDrawShape,
758 scrollTextNode ));
760 mpMetaFile = mpDrawShape->forceScrollTextMetaFile();
762 // make scroll text invisible for slide transition bitmaps
763 mpDrawShape->setVisibility(false);
765 basegfx::B2DRectangle aScrollRect, aPaintRect;
766 ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
767 aPaintRect,
768 mpMetaFile ),
769 "ActivityImpl::ActivityImpl(): Could not extract "
770 "scroll anim rectangles from mtf" );
772 maScrollRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
773 aScrollRect );
774 maPaintRectangleLogic = vcl::unotools::rectangleFromB2DRectangle(
775 aPaintRect );
777 maShapeAttrLayer.createAttributeLayer(mpDrawShape);
779 uno::Reference<drawing::XShape> const xShape( mpDrawShape->getXShape() );
780 uno::Reference<beans::XPropertySet> const xProps( xShape, uno::UNO_QUERY_THROW );
782 getPropertyValue( meAnimKind, xProps, "TextAnimationKind" );
783 OSL_ASSERT( meAnimKind != drawing::TextAnimationKind_NONE );
784 mbAlternate = (meAnimKind == drawing::TextAnimationKind_ALTERNATE);
785 mbScrollIn = (meAnimKind == drawing::TextAnimationKind_SLIDE);
787 // adopted from in AInfoBlinkText::ImplInit():
788 sal_Int16 nRepeat(0);
789 getPropertyValue( nRepeat, xProps, "TextAnimationCount" );
790 mnRepeat = nRepeat;
792 if(mbAlternate)
794 // force visible when started for scroll-forth-and-back, because
795 // slide has been coming in with visible text in the middle:
796 mbVisibleWhenStarted = true;
798 else
800 getPropertyValue( mbVisibleWhenStarted, xProps,
801 "TextAnimationStartInside" );
804 // set visible when stopped
805 getPropertyValue( mbVisibleWhenStopped, xProps,
806 "TextAnimatiogonStopInside" );
807 // rotation:
808 getPropertyValue( mfRotationAngle, xProps,
809 "RotateAngle" );
810 mfRotationAngle /= -100.0; // (switching direction)
812 // set frequency
813 sal_Int16 nDelay(0);
814 getPropertyValue( nDelay, xProps, "TextAnimationDelay" );
815 // set delay if not automatic
816 mnFrequency = (nDelay ? nDelay :
817 // default:
818 meAnimKind == drawing::TextAnimationKind_BLINK
819 ? 250 : 50 );
821 // adopted from in AInfoScrollText::ImplInit():
823 // If it is a simple m_bScrollIn, reset some parameters
824 if( DoScrollIn() )
826 // most parameters are set correctly from the dialog logic, but
827 // eg VisibleWhenStopped is grayed out and needs to be corrected here.
828 mbVisibleWhenStopped = true;
829 mbVisibleWhenStarted = false;
830 mnRepeat = 0;
833 // Get animation direction
834 getPropertyValue( meDirection, xProps, "TextAnimationDirection" );
836 // Get step width. Negative means pixel, positive logical units
837 getPropertyValue( mnStepWidth, xProps, "TextAnimationAmount" );
839 maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler(
840 mpListener );
843 bool ActivityImpl::enableAnimations()
845 mbIsActive = true;
846 return maContext.mrActivitiesQueue.addActivity( std::dynamic_pointer_cast<Activity>(shared_from_this()) );
849 void ActivityImpl::dispose()
851 if( !mbIsDisposed )
853 end();
855 // only remove subset here, since end() is called on slide end
856 // (and we must not spoil the slide preview bitmap with scroll
857 // text)
858 maShapeAttrLayer.reset();
859 if( mpDrawShape )
861 // TODO(Q3): Doing this manually, instead of using
862 // ShapeSubset. This is because of lifetime issues
863 // (ShapeSubset generates circular references to parent
864 // shape)
865 DrawShapeSharedPtr pParent( mpParentDrawShape.lock() );
866 if( pParent )
867 maContext.mpSubsettableShapeManager->revokeSubset(
868 pParent,
869 mpDrawShape );
872 mpMetaFile.reset();
873 mpDrawShape.reset();
874 mpParentDrawShape.reset();
875 mpWakeupEvent.reset();
876 maContext.dispose();
877 mbIsDisposed = true;
879 maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler(
880 mpListener );
884 double ActivityImpl::calcTimeLag() const
886 return 0.0;
889 bool ActivityImpl::isActive() const
891 return mbIsActive;
894 void ActivityImpl::dequeued()
896 // not used here
899 void ActivityImpl::end()
901 // not used here
902 mbIsActive = false;
904 if( mbIsShapeAnimated )
906 maContext.mpSubsettableShapeManager->leaveAnimationMode( mpDrawShape );
907 mbIsShapeAnimated = false;
911 } // anon namespace
913 namespace slideshow {
914 namespace internal {
916 std::shared_ptr<Activity> createDrawingLayerAnimActivity(
917 SlideShowContext const& rContext,
918 std::shared_ptr<DrawShape> const& pDrawShape )
920 std::shared_ptr<Activity> pActivity;
924 std::shared_ptr<WakeupEvent> const pWakeupEvent(
925 new WakeupEvent( rContext.mrEventQueue.getTimer(),
926 rContext.mrActivitiesQueue ) );
927 pActivity.reset( new ActivityImpl( rContext, pWakeupEvent, pDrawShape ) );
928 pWakeupEvent->setActivity( pActivity );
930 catch( uno::RuntimeException& )
932 throw;
934 catch( uno::Exception& )
936 // translate any error into empty factory product.
937 SAL_WARN( "slideshow", comphelper::anyToString( cppu::getCaughtException() ) );
940 return pActivity;
943 } // namespace internal
944 } // namespace presentation
946 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */