1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include "ppt97animations.hxx"
22 #include <svx/svdobj.hxx>
24 #include <tools/stream.hxx>
25 #include <svx/unoapi.hxx>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 #include <CustomAnimationPreset.hxx>
29 #include <com/sun/star/presentation/TextAnimationType.hpp>
30 #include <com/sun/star/presentation/EffectNodeType.hpp>
31 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
33 using namespace ::com::sun::star
;
35 void Ppt97AnimationInfoAtom::ReadStream( SvStream
& rIn
)
38 rIn
.ReadUInt32( nTmp
);
39 nDimColor
= Color(ColorTransparency
, nTmp
);
40 rIn
.ReadUInt32( nFlags
);
41 rIn
.ReadUInt32( nSoundRef
);
42 rIn
.ReadInt32( nDelayTime
);
43 rIn
.ReadUInt16( nOrderID
);
44 rIn
.ReadUInt16( nSlideCount
);
45 rIn
.ReadUChar( nBuildType
);
46 rIn
.ReadUChar( nFlyMethod
);
47 rIn
.ReadUChar( nFlyDirection
);
48 rIn
.ReadUChar( nAfterEffect
);
49 rIn
.ReadUChar( nSubEffect
);
50 rIn
.ReadUChar( nOLEVerb
);
51 rIn
.ReadUChar( nUnknown1
);
52 rIn
.ReadUChar( nUnknown2
);
55 Ppt97Animation::Ppt97Animation( SvStream
& rInputStream
)
58 , m_bHasSpecialDuration(false)
59 , m_fDurationInSeconds(0.001)
61 m_aAtom
.ReadStream( rInputStream
);
64 bool Ppt97Animation::operator < ( const Ppt97Animation
& rAnimation
) const
66 return m_aAtom
.nOrderID
< rAnimation
.m_aAtom
.nOrderID
;
68 bool Ppt97Animation::operator > ( const Ppt97Animation
& rAnimation
) const
70 return m_aAtom
.nOrderID
> rAnimation
.m_aAtom
.nOrderID
;
72 bool Ppt97Animation::HasEffect() const
74 return m_aAtom
.nBuildType
!= 0;
76 bool Ppt97Animation::HasParagraphEffect() const
78 return m_aAtom
.nBuildType
> 1;
80 sal_Int32
Ppt97Animation::GetParagraphLevel() const
82 sal_Int32 nParagraphLevel
= 0;
83 if(m_aAtom
.nBuildType
>1)
84 nParagraphLevel
= m_aAtom
.nBuildType
-1;
85 return nParagraphLevel
;
87 bool Ppt97Animation::HasSoundEffect() const
89 return m_aAtom
.nSoundRef
&& m_aAtom
.nFlags
& 0x0010;
91 bool Ppt97Animation::HasStopPreviousSound() const
93 return m_aAtom
.nFlags
& 0x0040;
95 bool Ppt97Animation::HasReverseOrder() const
97 return m_aAtom
.nFlags
& 0x001;
99 bool Ppt97Animation::HasAnimateAssociatedShape() const
101 return m_aAtom
.nFlags
& 0x004000;
103 bool Ppt97Animation::HasAfterEffect() const
105 return m_aAtom
.nAfterEffect
!= 0;
107 bool Ppt97Animation::HasAfterEffect_ChangeColor() const
109 return m_aAtom
.nAfterEffect
== 1;
111 bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
113 return m_aAtom
.nAfterEffect
== 2;
116 bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
118 return m_aAtom
.nAfterEffect
== 3;
121 void Ppt97Animation::SetSoundFileUrl( const OUString
& rSoundFileUrl
)
123 m_aSoundFileUrl
= rSoundFileUrl
;
126 double Ppt97Animation::GetDelayTimeInSeconds() const
128 return m_aAtom
.nDelayTime
!= 0X7FFFFFFF ? m_aAtom
.nDelayTime
/1000.0 : 0.0;
131 bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds
) const
134 if( m_bHasSpecialDuration
)
135 rfDurationInSeconds
= m_fDurationInSeconds
;
136 return m_bHasSpecialDuration
;
139 bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay
) const
142 switch(GetTextAnimationType())
144 case presentation::TextAnimationType::BY_LETTER
:
145 rfTextIterationDelay
= 0.075;
148 case presentation::TextAnimationType::BY_WORD
:
149 rfTextIterationDelay
= 0.3;
158 void Ppt97Animation::SetDimColor( Color nDimColor
)
160 m_aAtom
.nDimColor
= nDimColor
;
162 void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate
)
166 //the appear effect cannot be animated without text
167 if( GetPresetId() == "ooo-entrance-appear" )
169 //the random effect may be the appear effect and then has the same problem
170 if( GetPresetId() == "ooo-entrance-random" )
172 //this case is not 100% correct -> feel free to complete
173 //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
174 SAL_INFO("sd", "you tried to deselect the animation of the form for random animation-> this has been refused");
181 m_aAtom
.nFlags
= m_aAtom
.nFlags
| 0x004000;
182 else if( HasAnimateAssociatedShape() )
184 m_aAtom
.nFlags
= m_aAtom
.nFlags
^ 0x004000;
188 sal_Int16
Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
190 sal_Int16 nRet
= presentation::EffectNodeType::ON_CLICK
;
191 if( m_aAtom
.nFlags
& 0x04 )
193 nRet
= presentation::EffectNodeType::AFTER_PREVIOUS
;
198 sal_Int16
Ppt97Animation::GetTextAnimationType() const
200 sal_Int16 nRet
= presentation::TextAnimationType::BY_PARAGRAPH
;
201 switch( m_aAtom
.nSubEffect
)
206 nRet
= presentation::TextAnimationType::BY_LETTER
;
209 nRet
= presentation::TextAnimationType::BY_WORD
;
214 OUString
const & Ppt97Animation::GetPresetId() const
219 OUString
const & Ppt97Animation::GetPresetSubType() const
225 void Ppt97Animation::ClearCacheData() const
229 m_bHasSpecialDuration
= false;
230 m_fDurationInSeconds
= 0.001;
232 void Ppt97Animation::UpdateCacheData() const
241 m_bDirtyCache
= false;
245 switch( m_aAtom
.nFlyMethod
)
248 m_aPresetId
= "ooo-entrance-appear"; // --- appear ---
251 m_aPresetId
= "ooo-entrance-random"; // --- random ---
253 case 0x02: // --- blinds effect ---
255 switch ( m_aAtom
.nFlyDirection
)
258 m_aPresetId
= "ooo-entrance-venetian-blinds";
259 m_aSubType
= "horizontal"; // horizontal
262 m_aPresetId
= "ooo-entrance-venetian-blinds";
263 m_aSubType
= "vertical"; // vertical
268 case 0x03: // --- (hor/ver) shifted appear ---
270 switch ( m_aAtom
.nFlyDirection
)
273 m_aPresetId
= "ooo-entrance-checkerboard";
274 m_aSubType
= "across"; // vertical ???
277 m_aPresetId
= "ooo-entrance-checkerboard";
278 m_aSubType
= "downward"; // horizontal ???
284 m_aPresetId
= "ooo-entrance-dissolve-in";
286 case 0x08: // --- (hor/ver) lines ---
288 switch ( m_aAtom
.nFlyDirection
)
291 m_aPresetId
= "ooo-entrance-random-bars";
292 m_aSubType
= "vertical"; // horizontal ???
295 m_aPresetId
= "ooo-entrance-random-bars";
296 m_aSubType
= "horizontal"; // vertical ???
301 case 0x09: // --- diagonal ---
303 switch ( m_aAtom
.nFlyDirection
)
306 m_aPresetId
= "ooo-entrance-diagonal-squares";
307 m_aSubType
= "left-to-top"; // to left top
310 m_aPresetId
= "ooo-entrance-diagonal-squares";
311 m_aSubType
= "right-to-top"; // to right top
314 m_aPresetId
= "ooo-entrance-diagonal-squares";
315 m_aSubType
= "left-to-bottom"; // to left bottom
318 m_aPresetId
= "ooo-entrance-diagonal-squares";
319 m_aSubType
= "right-to-bottom"; // to right bottom
324 case 0x0a: // --- roll/wipe ---
326 switch ( m_aAtom
.nFlyDirection
)
329 m_aPresetId
= "ooo-entrance-wipe";
330 m_aSubType
= "from-right"; // from right
333 m_aPresetId
= "ooo-entrance-wipe";
334 m_aSubType
= "from-bottom"; // from bottom
337 m_aPresetId
= "ooo-entrance-wipe";
338 m_aSubType
= "from-left"; // from left
341 m_aPresetId
= "ooo-entrance-wipe";
342 m_aSubType
= "from-top"; // from top
347 case 0x0b: //--- fade in ---
349 switch ( m_aAtom
.nFlyDirection
)
352 m_aPresetId
= "ooo-entrance-box";
353 m_aSubType
= "out"; // from center
356 m_aPresetId
= "ooo-entrance-box";
357 m_aSubType
= "in"; // to center
362 case 0x0c: // --- text effects ---
364 switch ( m_aAtom
.nFlyDirection
)
367 m_aPresetId
= "ooo-entrance-fly-in";
368 m_aSubType
= "from-left";
372 m_aPresetId
= "ooo-entrance-fly-in";
373 m_aSubType
= "from-top";
376 m_aPresetId
= "ooo-entrance-fly-in";
377 m_aSubType
= "from-right";
380 m_aPresetId
= "ooo-entrance-fly-in";
381 m_aSubType
= "from-bottom";
384 m_aPresetId
= "ooo-entrance-fly-in";
385 m_aSubType
= "from-top-left";
388 m_aPresetId
= "ooo-entrance-fly-in";
389 m_aSubType
= "from-top-right";
392 m_aPresetId
= "ooo-entrance-fly-in";
393 m_aSubType
= "from-bottom-left";
396 m_aPresetId
= "ooo-entrance-fly-in";
397 m_aSubType
= "from-bottom-right";
399 case 0x8: // -- short text effects --
400 m_aPresetId
= "ooo-entrance-peek-in";
401 m_aSubType
= "from-left";
404 m_aPresetId
= "ooo-entrance-peek-in";
405 m_aSubType
= "from-bottom";
408 m_aPresetId
= "ooo-entrance-peek-in";
409 m_aSubType
= "from-right";
412 m_aPresetId
= "ooo-entrance-peek-in";
413 m_aSubType
= "from-top";
415 case 0xc: // -- slow text effects --
417 m_aPresetId
= "ooo-entrance-fly-in-slow";
418 m_aSubType
= "from-left";
423 m_aPresetId
= "ooo-entrance-fly-in-slow";
424 m_aSubType
= "from-top";
429 m_aPresetId
= "ooo-entrance-fly-in-slow";
430 m_aSubType
= "from-right";
435 m_aPresetId
= "ooo-entrance-fly-in-slow";
436 m_aSubType
= "from-bottom";
439 case 0x10: // --- zoom ---
440 m_aPresetId
= "ooo-entrance-zoom";
444 m_aPresetId
= "ooo-entrance-zoom";
445 m_aSubType
= "in-slightly";
448 m_aPresetId
= "ooo-entrance-zoom";
452 m_aPresetId
= "ooo-entrance-zoom";
453 m_aSubType
= "out-slightly";
456 m_aPresetId
= "ooo-entrance-zoom";
457 m_aSubType
= "in-from-screen-center";
460 m_aPresetId
= "ooo-entrance-zoom";
461 m_aSubType
= "out-from-screen-center";
463 case 0x16: // --- stretch ---
464 m_aPresetId
= "ooo-entrance-stretchy";
465 m_aSubType
= "across";
468 m_aPresetId
= "ooo-entrance-stretchy";
469 m_aSubType
= "from-left";
472 m_aPresetId
= "ooo-entrance-stretchy";
473 m_aSubType
= "from-top";
476 m_aPresetId
= "ooo-entrance-stretchy";
477 m_aSubType
= "from-right";
480 m_aPresetId
= "ooo-entrance-stretchy";
481 m_aSubType
= "from-bottom";
483 case 0x1b: // --- rotate ---
484 m_aPresetId
= "ooo-entrance-swivel";
485 m_aSubType
= "vertical";
487 case 0x1c: // --- spirale ---
488 m_aPresetId
= "ooo-entrance-spiral-in";
493 case 0x0d: // --- open/close ---
495 switch ( m_aAtom
.nFlyDirection
)
498 m_aPresetId
= "ooo-entrance-split";
499 m_aSubType
= "horizontal-out"; //horizontal open
502 m_aPresetId
= "ooo-entrance-split";
503 m_aSubType
= "horizontal-in"; //horizontal close
506 m_aPresetId
= "ooo-entrance-split";
507 m_aSubType
= "vertical-out"; // vertical open
510 m_aPresetId
= "ooo-entrance-split";
511 m_aSubType
= "vertical-in"; // vertical close
516 case 0x0e: // --- blink ---
518 m_aPresetId
= "ooo-entrance-flash-once";
519 switch ( m_aAtom
.nFlyDirection
)
522 m_fDurationInSeconds
= 0.075;
523 m_bHasSpecialDuration
= true;
526 m_fDurationInSeconds
= 0.5;
527 m_bHasSpecialDuration
= true;
530 m_fDurationInSeconds
= 1.0;
531 m_bHasSpecialDuration
= true;
538 m_aPresetId
= "ooo-entrance-appear";
539 OSL_FAIL("no effect mapped");
543 m_bDirtyCache
= false;
546 void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject
* pObj
)
551 if( !pObj
|| !pObj
->getSdrPageFromSdrObject() )
553 OSL_FAIL("no valid SdrObject or page found for ppt import");
557 uno::Reference
< drawing::XShape
> xShape
= GetXShapeForSdrObject( pObj
);
560 OSL_FAIL("no XShape interface found for ppt import");
563 ::sd::MainSequencePtr pMainSequence
= static_cast<SdPage
*>(pObj
->getSdrPageFromSdrObject())->getMainSequence();
566 OSL_FAIL("no MainSequence found for ppt import");
570 const ::sd::CustomAnimationPresets
& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
571 ::sd::CustomAnimationPresetPtr
pPreset( rPresets
.getEffectDescriptor( GetPresetId() ) );
574 OSL_FAIL("no suitable preset found for ppt import");
578 //--------------start doing something
580 //1. ------ create an effect from the presets ------
581 ::sd::CustomAnimationEffectPtr pEffect
= std::make_shared
<::sd::CustomAnimationEffect
>( pPreset
->create( GetPresetSubType() ) );
583 //2. ------ adapt the created effect ------
585 // set the shape targeted by this effect
586 pEffect
->setTarget( css::uno::Any( xShape
) );
588 pEffect
->setBegin( GetDelayTimeInSeconds() );
590 // some effects need a different duration than that of the mapped preset effect
591 double fDurationInSeconds
= 1.0; //in seconds
592 if( GetSpecialDuration( fDurationInSeconds
) )
593 pEffect
->setDuration( fDurationInSeconds
);
596 if( HasAfterEffect() )
598 pEffect
->setHasAfterEffect( true );
599 if( HasAfterEffect_ChangeColor() )
600 pEffect
->setDimColor( uno::Any( GetDimColor() ) );
602 pEffect
->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
606 if( HasSoundEffect() )
607 pEffect
->createAudio( uno::Any( m_aSoundFileUrl
) );
610 pEffect
->setIterateType( GetTextAnimationType() );
612 // some effects need a different delay between text iteration than that of the mapped preset effect
613 double fTextIterationDelay
= 1.0;
614 if( GetSpecialTextIterationDelay( fTextIterationDelay
) )
615 pEffect
->setIterateInterval( fTextIterationDelay
);
617 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
618 pEffect
->setNodeType( GetEffectNodeType() );
620 //set stop sound effect
621 if( HasStopPreviousSound() )
622 pEffect
->setStopAudio();
624 // append the effect to the main sequence
625 if( !HasParagraphEffect() )
627 // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
628 pEffect
->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE
);
631 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
632 pMainSequence
->append( pEffect
);
633 if( HasParagraphEffect() )
635 sal_Int32 nParagraphLevel
= GetParagraphLevel();
636 double fDelaySeconds
= GetDelayTimeInSeconds();
637 bool bAnimateAssociatedShape
= HasAnimateAssociatedShape();//or only text
638 bool bTextReverse
= HasReverseOrder();
640 // now create effects for each paragraph
641 ::sd::CustomAnimationTextGroupPtr pGroup
= pMainSequence
->
642 createTextGroup( pEffect
, nParagraphLevel
, fDelaySeconds
, bAnimateAssociatedShape
, bTextReverse
);
646 const ::sd::EffectSequence
& rEffects
= pGroup
->getEffects();
648 ::sd::CustomAnimationEffectPtr pLastEffect
;
649 sal_Int32 nIndex
= 0;
650 for( const auto& rxEffect
: rEffects
)
652 ::sd::CustomAnimationEffectPtr
pGroupEffect(rxEffect
);
654 ////todo? if( nIndex > 1 && pLastEffect && HasSoundEffect() )
655 //// pLastEffect->setStopAudio();
658 pGroupEffect
->setNodeType( GetEffectNodeType() );
660 else if( nIndex
> 0 )
662 bool bAtParagraphBegin
= false;
664 bAtParagraphBegin
= pGroupEffect
->getParaDepth() < nParagraphLevel
;
666 bAtParagraphBegin
= !pLastEffect
|| pLastEffect
->getParaDepth() < nParagraphLevel
;
667 if( bAtParagraphBegin
)
668 pGroupEffect
->setNodeType( GetEffectNodeType() );
669 else if( GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH
)
670 pGroupEffect
->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS
);
672 pGroupEffect
->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS
);
674 pLastEffect
= pGroupEffect
;
679 pMainSequence
->rebuild();
682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */