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 <CustomAnimationPreset.hxx>
28 #include <com/sun/star/presentation/TextAnimationType.hpp>
29 #include <com/sun/star/presentation/EffectNodeType.hpp>
30 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
32 using namespace ::com::sun::star
;
34 void Ppt97AnimationInfoAtom::ReadStream( SvStream
& rIn
)
37 rIn
.ReadUInt32( nTmp
);
38 nDimColor
= Color(nTmp
);
39 rIn
.ReadUInt32( nFlags
);
40 rIn
.ReadUInt32( nSoundRef
);
41 rIn
.ReadInt32( nDelayTime
);
42 rIn
.ReadUInt16( nOrderID
);
43 rIn
.ReadUInt16( nSlideCount
);
44 rIn
.ReadUChar( nBuildType
);
45 rIn
.ReadUChar( nFlyMethod
);
46 rIn
.ReadUChar( nFlyDirection
);
47 rIn
.ReadUChar( nAfterEffect
);
48 rIn
.ReadUChar( nSubEffect
);
49 rIn
.ReadUChar( nOLEVerb
);
50 rIn
.ReadUChar( nUnknown1
);
51 rIn
.ReadUChar( nUnknown2
);
54 Ppt97Animation::Ppt97Animation( SvStream
& rInputStream
)
57 , m_bHasSpecialDuration(false)
58 , m_fDurationInSeconds(0.001)
60 m_aAtom
.ReadStream( rInputStream
);
63 bool Ppt97Animation::operator < ( const Ppt97Animation
& rAnimation
) const
65 return m_aAtom
.nOrderID
< rAnimation
.m_aAtom
.nOrderID
;
67 bool Ppt97Animation::operator > ( const Ppt97Animation
& rAnimation
) const
69 return m_aAtom
.nOrderID
> rAnimation
.m_aAtom
.nOrderID
;
71 bool Ppt97Animation::HasEffect() const
73 return m_aAtom
.nBuildType
!= 0;
75 bool Ppt97Animation::HasParagraphEffect() const
77 return m_aAtom
.nBuildType
> 1;
79 sal_Int32
Ppt97Animation::GetParagraphLevel() const
81 sal_Int32 nParagraphLevel
= 0;
82 if(m_aAtom
.nBuildType
>1)
83 nParagraphLevel
= m_aAtom
.nBuildType
-1;
84 return nParagraphLevel
;
86 bool Ppt97Animation::HasSoundEffect() const
88 return m_aAtom
.nSoundRef
&& m_aAtom
.nFlags
& 0x0010;
90 bool Ppt97Animation::HasStopPreviousSound() const
92 return m_aAtom
.nFlags
& 0x0040;
94 bool Ppt97Animation::HasReverseOrder() const
96 return m_aAtom
.nFlags
& 0x001;
98 bool Ppt97Animation::HasAnimateAssociatedShape() const
100 return m_aAtom
.nFlags
& 0x004000;
102 bool Ppt97Animation::HasAfterEffect() const
104 return m_aAtom
.nAfterEffect
!= 0;
106 bool Ppt97Animation::HasAfterEffect_ChangeColor() const
108 return m_aAtom
.nAfterEffect
== 1;
110 bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
112 return m_aAtom
.nAfterEffect
== 2;
115 bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
117 return m_aAtom
.nAfterEffect
== 3;
120 void Ppt97Animation::SetSoundFileUrl( const OUString
& rSoundFileUrl
)
122 m_aSoundFileUrl
= rSoundFileUrl
;
125 double Ppt97Animation::GetDelayTimeInSeconds() const
127 return m_aAtom
.nDelayTime
!= 0X7FFFFFFF ? m_aAtom
.nDelayTime
/1000.0 : 0.0;
130 bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds
) const
133 if( m_bHasSpecialDuration
)
134 rfDurationInSeconds
= m_fDurationInSeconds
;
135 return m_bHasSpecialDuration
;
138 bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay
) const
141 switch(GetTextAnimationType())
143 case presentation::TextAnimationType::BY_LETTER
:
144 rfTextIterationDelay
= 0.075;
147 case presentation::TextAnimationType::BY_WORD
:
148 rfTextIterationDelay
= 0.3;
157 void Ppt97Animation::SetDimColor( Color nDimColor
)
159 m_aAtom
.nDimColor
= nDimColor
;
161 void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate
)
165 //the appear effect cannot be animated without text
166 if( GetPresetId() == "ooo-entrance-appear" )
168 //the random effect may be the appear effect and than has the same problem
169 if( GetPresetId() == "ooo-entrance-random" )
171 //this case is not 100% correct -> feel free to complete
172 //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
173 SAL_INFO("sd", "you tried to deselect the animation of the form for random animation-> this has been refused");
180 m_aAtom
.nFlags
= m_aAtom
.nFlags
| 0x004000;
181 else if( HasAnimateAssociatedShape() )
183 m_aAtom
.nFlags
= m_aAtom
.nFlags
^ 0x004000;
187 sal_Int16
Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
189 sal_Int16 nRet
= presentation::EffectNodeType::ON_CLICK
;
190 if( m_aAtom
.nFlags
& 0x04 )
192 nRet
= presentation::EffectNodeType::AFTER_PREVIOUS
;
197 sal_Int16
Ppt97Animation::GetTextAnimationType() const
199 sal_Int16 nRet
= presentation::TextAnimationType::BY_PARAGRAPH
;
200 switch( m_aAtom
.nSubEffect
)
205 nRet
= presentation::TextAnimationType::BY_LETTER
;
208 nRet
= presentation::TextAnimationType::BY_WORD
;
213 OUString
const & Ppt97Animation::GetPresetId() const
218 OUString
const & Ppt97Animation::GetPresetSubType() const
224 void Ppt97Animation::ClearCacheData() const
228 m_bHasSpecialDuration
= false;
229 m_fDurationInSeconds
= 0.001;
231 void Ppt97Animation::UpdateCacheData() const
240 m_bDirtyCache
= false;
244 switch( m_aAtom
.nFlyMethod
)
247 m_aPresetId
= "ooo-entrance-appear"; // --- appear ---
250 m_aPresetId
= "ooo-entrance-random"; // --- random ---
252 case 0x02: // --- blinds effect ---
254 switch ( m_aAtom
.nFlyDirection
)
257 m_aPresetId
= "ooo-entrance-venetian-blinds";
258 m_aSubType
= "horizontal"; // horizontal
261 m_aPresetId
= "ooo-entrance-venetian-blinds";
262 m_aSubType
= "vertical"; // vertical
267 case 0x03: // --- (hor/ver) shifted appear ---
269 switch ( m_aAtom
.nFlyDirection
)
272 m_aPresetId
= "ooo-entrance-checkerboard";
273 m_aSubType
= "across"; // vertical ???
276 m_aPresetId
= "ooo-entrance-checkerboard";
277 m_aSubType
= "downward"; // horizontal ???
283 m_aPresetId
= "ooo-entrance-dissolve-in";
285 case 0x08: // --- (hor/ver) lines ---
287 switch ( m_aAtom
.nFlyDirection
)
290 m_aPresetId
= "ooo-entrance-random-bars";
291 m_aSubType
= "vertical"; // horizontal ???
294 m_aPresetId
= "ooo-entrance-random-bars";
295 m_aSubType
= "horizontal"; // vertical ???
300 case 0x09: // --- diagonal ---
302 switch ( m_aAtom
.nFlyDirection
)
305 m_aPresetId
= "ooo-entrance-diagonal-squares";
306 m_aSubType
= "left-to-top"; // to left top
309 m_aPresetId
= "ooo-entrance-diagonal-squares";
310 m_aSubType
= "right-to-top"; // to right top
313 m_aPresetId
= "ooo-entrance-diagonal-squares";
314 m_aSubType
= "left-to-bottom"; // to left bottom
317 m_aPresetId
= "ooo-entrance-diagonal-squares";
318 m_aSubType
= "right-to-bottom"; // to right bottom
323 case 0x0a: // --- roll/wipe ---
325 switch ( m_aAtom
.nFlyDirection
)
328 m_aPresetId
= "ooo-entrance-wipe";
329 m_aSubType
= "from-right"; // from right
332 m_aPresetId
= "ooo-entrance-wipe";
333 m_aSubType
= "from-bottom"; // from bottom
336 m_aPresetId
= "ooo-entrance-wipe";
337 m_aSubType
= "from-left"; // from left
340 m_aPresetId
= "ooo-entrance-wipe";
341 m_aSubType
= "from-top"; // from top
346 case 0x0b: //--- fade in ---
348 switch ( m_aAtom
.nFlyDirection
)
351 m_aPresetId
= "ooo-entrance-box";
352 m_aSubType
= "out"; // from center
355 m_aPresetId
= "ooo-entrance-box";
356 m_aSubType
= "in"; // to center
361 case 0x0c: // --- text effects ---
363 switch ( m_aAtom
.nFlyDirection
)
366 m_aPresetId
= "ooo-entrance-fly-in";
367 m_aSubType
= "from-left";
371 m_aPresetId
= "ooo-entrance-fly-in";
372 m_aSubType
= "from-top";
375 m_aPresetId
= "ooo-entrance-fly-in";
376 m_aSubType
= "from-right";
379 m_aPresetId
= "ooo-entrance-fly-in";
380 m_aSubType
= "from-bottom";
383 m_aPresetId
= "ooo-entrance-fly-in";
384 m_aSubType
= "from-top-left";
387 m_aPresetId
= "ooo-entrance-fly-in";
388 m_aSubType
= "from-top-right";
391 m_aPresetId
= "ooo-entrance-fly-in";
392 m_aSubType
= "from-bottom-left";
395 m_aPresetId
= "ooo-entrance-fly-in";
396 m_aSubType
= "from-bottom-right";
398 case 0x8: // -- short text effects --
399 m_aPresetId
= "ooo-entrance-peek-in";
400 m_aSubType
= "from-left";
403 m_aPresetId
= "ooo-entrance-peek-in";
404 m_aSubType
= "from-bottom";
407 m_aPresetId
= "ooo-entrance-peek-in";
408 m_aSubType
= "from-right";
411 m_aPresetId
= "ooo-entrance-peek-in";
412 m_aSubType
= "from-top";
414 case 0xc: // -- slow text effects --
416 m_aPresetId
= "ooo-entrance-fly-in-slow";
417 m_aSubType
= "from-left";
422 m_aPresetId
= "ooo-entrance-fly-in-slow";
423 m_aSubType
= "from-top";
428 m_aPresetId
= "ooo-entrance-fly-in-slow";
429 m_aSubType
= "from-right";
434 m_aPresetId
= "ooo-entrance-fly-in-slow";
435 m_aSubType
= "from-bottom";
438 case 0x10: // --- zoom ---
439 m_aPresetId
= "ooo-entrance-zoom";
443 m_aPresetId
= "ooo-entrance-zoom";
444 m_aSubType
= "in-slightly";
447 m_aPresetId
= "ooo-entrance-zoom";
451 m_aPresetId
= "ooo-entrance-zoom";
452 m_aSubType
= "out-slightly";
455 m_aPresetId
= "ooo-entrance-zoom";
456 m_aSubType
= "in-from-screen-center";
459 m_aPresetId
= "ooo-entrance-zoom";
460 m_aSubType
= "out-from-screen-center";
462 case 0x16: // --- stretch ---
463 m_aPresetId
= "ooo-entrance-stretchy";
464 m_aSubType
= "across";
467 m_aPresetId
= "ooo-entrance-stretchy";
468 m_aSubType
= "from-left";
471 m_aPresetId
= "ooo-entrance-stretchy";
472 m_aSubType
= "from-top";
475 m_aPresetId
= "ooo-entrance-stretchy";
476 m_aSubType
= "from-right";
479 m_aPresetId
= "ooo-entrance-stretchy";
480 m_aSubType
= "from-bottom";
482 case 0x1b: // --- rotate ---
483 m_aPresetId
= "ooo-entrance-swivel";
484 m_aSubType
= "vertical";
486 case 0x1c: // --- spirale ---
487 m_aPresetId
= "ooo-entrance-spiral-in";
492 case 0x0d: // --- open/close ---
494 switch ( m_aAtom
.nFlyDirection
)
497 m_aPresetId
= "ooo-entrance-split";
498 m_aSubType
= "horizontal-out"; //horizontal open
501 m_aPresetId
= "ooo-entrance-split";
502 m_aSubType
= "horizontal-in"; //horizontal close
505 m_aPresetId
= "ooo-entrance-split";
506 m_aSubType
= "vertical-out"; // vertical open
509 m_aPresetId
= "ooo-entrance-split";
510 m_aSubType
= "vertical-in"; // vertical close
515 case 0x0e: // --- blink ---
517 m_aPresetId
= "ooo-entrance-flash-once";
518 switch ( m_aAtom
.nFlyDirection
)
521 m_fDurationInSeconds
= 0.075;
522 m_bHasSpecialDuration
= true;
525 m_fDurationInSeconds
= 0.5;
526 m_bHasSpecialDuration
= true;
529 m_fDurationInSeconds
= 1.0;
530 m_bHasSpecialDuration
= true;
537 m_aPresetId
= "ooo-entrance-appear";
538 OSL_FAIL("no effect mapped");
542 m_bDirtyCache
= false;
545 void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject
* pObj
)
550 if( !pObj
|| !pObj
->getSdrPageFromSdrObject() )
552 OSL_FAIL("no valid SdrObject or page found for ppt import");
556 uno::Reference
< drawing::XShape
> xShape
= GetXShapeForSdrObject( pObj
);
559 OSL_FAIL("no XShape interface found for ppt import");
562 ::sd::MainSequencePtr pMainSequence
= static_cast<SdPage
*>(pObj
->getSdrPageFromSdrObject())->getMainSequence();
563 if( !pMainSequence
.get() )
565 OSL_FAIL("no MainSequence found for ppt import");
569 const ::sd::CustomAnimationPresets
& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
570 ::sd::CustomAnimationPresetPtr
pPreset( rPresets
.getEffectDescriptor( GetPresetId() ) );
573 OSL_FAIL("no suitable preset found for ppt import");
577 //--------------start doing something
579 //1. ------ create an effect from the presets ------
580 ::sd::CustomAnimationEffectPtr
pEffect( new ::sd::CustomAnimationEffect( pPreset
->create( GetPresetSubType() ) ) );
582 //2. ------ adapt the created effect ------
584 // set the shape targeted by this effect
585 pEffect
->setTarget( makeAny( xShape
) );
587 pEffect
->setBegin( GetDelayTimeInSeconds() );
589 // some effects need a different duration than that of the mapped preset effect
590 double fDurationInSeconds
= 1.0; //in seconds
591 if( GetSpecialDuration( fDurationInSeconds
) )
592 pEffect
->setDuration( fDurationInSeconds
);
595 if( HasAfterEffect() )
597 pEffect
->setHasAfterEffect( true );
598 if( HasAfterEffect_ChangeColor() )
599 pEffect
->setDimColor( uno::makeAny( GetDimColor() ) );
601 pEffect
->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
605 if( HasSoundEffect() )
606 pEffect
->createAudio( uno::makeAny( m_aSoundFileUrl
) );
609 pEffect
->setIterateType( GetTextAnimationType() );
611 // some effects need a different delay between text iteration than that of the mapped preset effect
612 double fTextIterationDelay
= 1.0;
613 if( GetSpecialTextIterationDelay( fTextIterationDelay
) )
614 pEffect
->setIterateInterval( fTextIterationDelay
);
616 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
617 pEffect
->setNodeType( GetEffectNodeType() );
619 //set stop sound effect
620 if( HasStopPreviousSound() )
621 pEffect
->setStopAudio();
623 // append the effect to the main sequence
624 if( !HasParagraphEffect() )
626 // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
627 pEffect
->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE
);
630 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
631 pMainSequence
->append( pEffect
);
632 if( HasParagraphEffect() )
634 sal_Int32 nParagraphLevel
= GetParagraphLevel();
635 double fDelaySeconds
= GetDelayTimeInSeconds();
636 bool bAnimateAssociatedShape
= HasAnimateAssociatedShape();//or only text
637 bool bTextReverse
= HasReverseOrder();
639 // now create effects for each paragraph
640 ::sd::CustomAnimationTextGroupPtr pGroup
= pMainSequence
->
641 createTextGroup( pEffect
, nParagraphLevel
, fDelaySeconds
, bAnimateAssociatedShape
, bTextReverse
);
645 const ::sd::EffectSequence
& rEffects
= pGroup
->getEffects();
647 ::sd::CustomAnimationEffectPtr pLastEffect
;
648 sal_Int32 nIndex
= 0;
649 for( const auto& rxEffect
: rEffects
)
651 ::sd::CustomAnimationEffectPtr
pGroupEffect(rxEffect
);
653 ////todo? if( nIndex > 1 && pLastEffect && HasSoundEffect() )
654 //// pLastEffect->setStopAudio();
657 pGroupEffect
->setNodeType( GetEffectNodeType() );
659 else if( nIndex
> 0 )
661 bool bAtParagraphBegin
= false;
663 bAtParagraphBegin
= pGroupEffect
->getParaDepth() < nParagraphLevel
;
665 bAtParagraphBegin
= !pLastEffect
|| pLastEffect
->getParaDepth() < nParagraphLevel
;
666 if( bAtParagraphBegin
)
667 pGroupEffect
->setNodeType( GetEffectNodeType() );
668 else if( GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH
)
669 pGroupEffect
->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS
);
671 pGroupEffect
->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS
);
673 pLastEffect
= pGroupEffect
;
678 pMainSequence
->rebuild();
681 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */