Update git submodules
[LibreOffice.git] / sd / source / filter / eppt / pptexanimations.cxx
blob79588352cfb2907d7b4f1c291786cb8f8e0ea468
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 .
20 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
21 #include <com/sun/star/animations/AnimationFill.hpp>
22 #include <com/sun/star/animations/AnimationRestart.hpp>
23 #include <com/sun/star/animations/Timing.hpp>
24 #include <com/sun/star/animations/Event.hpp>
25 #include <com/sun/star/animations/AnimationEndSync.hpp>
26 #include <com/sun/star/animations/EventTrigger.hpp>
27 #include <com/sun/star/presentation/EffectNodeType.hpp>
28 #include <com/sun/star/presentation/EffectPresetClass.hpp>
29 #include <com/sun/star/animations/AnimationNodeType.hpp>
30 #include <com/sun/star/animations/AnimationTransformType.hpp>
31 #include <com/sun/star/animations/AnimationCalcMode.hpp>
32 #include <com/sun/star/util/XCloneable.hpp>
33 #include <com/sun/star/animations/AnimationAdditiveMode.hpp>
34 #include <com/sun/star/animations/XAnimateSet.hpp>
35 #include <com/sun/star/animations/XAudio.hpp>
36 #include <com/sun/star/animations/XTransitionFilter.hpp>
37 #include <com/sun/star/animations/XAnimateColor.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimateTransform.hpp>
40 #include <com/sun/star/animations/ValuePair.hpp>
41 #include <com/sun/star/animations/AnimationColorSpace.hpp>
42 #include <com/sun/star/drawing/FillStyle.hpp>
43 #include <com/sun/star/drawing/LineStyle.hpp>
44 #include <com/sun/star/drawing/XDrawPage.hpp>
45 #include <com/sun/star/awt/FontWeight.hpp>
46 #include <com/sun/star/awt/FontUnderline.hpp>
47 #include <com/sun/star/awt/FontSlant.hpp>
48 #include <com/sun/star/container/XEnumerationAccess.hpp>
49 #include <com/sun/star/presentation/ParagraphTarget.hpp>
50 #include <com/sun/star/text/XSimpleText.hpp>
51 #include <com/sun/star/animations/XIterateContainer.hpp>
52 #include <com/sun/star/presentation/TextAnimationType.hpp>
54 #include <oox/ppt/pptfilterhelpers.hxx>
55 #include "pptexanimations.hxx"
56 #include "pptexsoundcollection.hxx"
57 #include "../ppt/pptanimations.hxx"
58 #include <filter/msfilter/escherex.hxx>
59 #include <osl/diagnose.h>
60 #include <tools/debug.hxx>
61 #include <comphelper/diagnose_ex.hxx>
62 #include <o3tl/string_view.hxx>
64 #include <algorithm>
66 using ::com::sun::star::uno::Any;
67 using ::com::sun::star::util::XCloneable;
68 using ::com::sun::star::uno::Reference;
69 using ::com::sun::star::uno::UNO_QUERY;
70 using ::com::sun::star::uno::UNO_QUERY_THROW;
71 using ::com::sun::star::uno::Sequence;
72 using ::com::sun::star::uno::Exception;
73 using ::com::sun::star::beans::NamedValue;
74 using ::com::sun::star::container::XEnumerationAccess;
75 using ::com::sun::star::container::XEnumeration;
77 using namespace ::com::sun::star::text;
78 using namespace ::com::sun::star::drawing;
79 using namespace ::com::sun::star::animations;
80 using namespace ::com::sun::star::presentation;
82 namespace ppt
85 static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
87 if ( eTranslateMode == TRANSLATE_NONE )
88 return;
90 if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
92 const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
93 while( p->mpAPIName )
95 if( rString.equalsAscii( p->mpAPIName ) )
96 break;
97 p++;
99 if( p->mpMSName )
101 if ( eTranslateMode & TRANSLATE_VALUE )
103 rString = "#";
104 rString += OUString::createFromAscii( p->mpMSName );
106 else
107 rString = OUString::createFromAscii( p->mpMSName );
110 else if ( eTranslateMode & TRANSLATE_MEASURE )
112 const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
113 const char* pSource[] = { "x", "y", "width", "height", nullptr };
114 sal_Int32 nIndex = 0;
116 const char** ps = pSource;
117 const char** pd = pDest;
119 while( *ps )
121 if (nIndex == -1)
122 nIndex = 0;
123 const OUString aSearch( OUString::createFromAscii( *ps ) );
124 while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
126 sal_Int32 nLength = aSearch.getLength();
127 if( nIndex && ( rString[nIndex-1] == '#' ) )
129 nIndex--;
130 nLength++;
133 const OUString aNew( OUString::createFromAscii( *pd ) );
134 rString = rString.replaceAt( nIndex, nLength, aNew );
135 nIndex += aNew.getLength();
137 ps++;
138 pd++;
143 sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType )
145 sal_uInt32 nPresetSubType = 0;
146 bool bTranslated = false;
148 if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
150 if ( nPresetId != 21 )
152 switch( nPresetId )
154 case 5 :
156 if ( rPresetSubType == u"downward" )
158 nPresetSubType = 5;
159 bTranslated = true;
161 else if ( rPresetSubType == u"across" )
163 nPresetSubType = 10;
164 bTranslated = true;
167 break;
168 case 17 :
170 if ( rPresetSubType == u"across" )
172 nPresetSubType = 10;
173 bTranslated = true;
176 break;
177 case 18 :
179 if ( rPresetSubType == u"right-to-top" )
181 nPresetSubType = 3;
182 bTranslated = true;
184 else if ( rPresetSubType == u"right-to-bottom" )
186 nPresetSubType = 6;
187 bTranslated = true;
189 else if ( rPresetSubType == u"left-to-top" )
191 nPresetSubType = 9;
192 bTranslated = true;
194 else if ( rPresetSubType == u"left-to-bottom" )
196 nPresetSubType = 12;
197 bTranslated = true;
200 break;
203 if ( !bTranslated )
205 const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
206 while( p->mpStrSubType )
208 if ( o3tl::equalsAscii( rPresetSubType, p->mpStrSubType ) )
210 nPresetSubType = p->mnID;
211 bTranslated = true;
212 break;
214 p++;
218 if ( !bTranslated )
219 nPresetSubType = o3tl::toUInt32(rPresetSubType);
220 return nPresetSubType;
223 const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
225 const char* pRet = nullptr;
226 int nFit = 0;
228 const oox::ppt::transition* p = oox::ppt::transition::getList();
229 while( p->mpName )
231 int nF = 0;
232 if ( nType == p->mnType )
233 nF += 4;
234 if ( nSubType == p->mnSubType )
235 nF += 2;
236 if ( bDirection == p->mbDirection )
237 nF += 1;
238 if ( nF > nFit )
240 pRet = p->mpName;
241 nFit = nF;
243 if ( nFit == 7 ) // maximum
244 break;
245 p++;
247 return pRet;
250 SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
252 rOut.WriteInt32( rNode.mnU1 );
253 rOut.WriteInt32( rNode.mnRestart );
254 rOut.WriteInt32( rNode.mnGroupType );
255 rOut.WriteInt32( rNode.mnFill );
256 rOut.WriteInt32( rNode.mnU3 );
257 rOut.WriteInt32( rNode.mnU4 );
258 rOut.WriteInt32( rNode.mnDuration );
259 rOut.WriteInt32( rNode.mnNodeType );
261 return rOut;
264 AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
265 mrSolverContainer ( rSolverContainer ),
266 mrExSoundCollection ( rExSoundCollection ),
267 mnCurrentGroup(0)
271 sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
273 sal_Int16 nFill = xNode->getFill();
274 //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
275 //#i119740 <Animation> The animation effect "Entrance->Flash Once" fails to play in Aoo while Aoo saves a .ppt to another .ppt and plays the saved one.
276 if ((xNode->getType() == AnimationNodeType::ANIMATE)
277 ||(xNode->getType() == AnimationNodeType::SET)
278 ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
280 if ( nFill == AnimationFill::DEFAULT )
281 return nFill;
284 if ( nFill == AnimationFill::DEFAULT )
286 nFill = nFillDefault;
288 if( nFill == AnimationFill::AUTO )
290 nFill = AnimationFill::REMOVE;
291 bool bIsIndefiniteTiming = true;
292 Any aAny = xNode->getDuration();
293 if( aAny.hasValue() )
295 Timing eTiming;
296 if( aAny >>= eTiming )
297 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
299 if ( bIsIndefiniteTiming )
301 aAny = xNode->getEnd();
302 if( aAny.hasValue() )
304 Timing eTiming;
305 if( aAny >>= eTiming )
306 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
308 if ( bIsIndefiniteTiming )
310 if ( !xNode->getRepeatCount().hasValue() )
312 aAny = xNode->getRepeatDuration();
313 if( aAny.hasValue() )
315 Timing eTiming;
316 if( aAny >>= eTiming )
317 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
319 if ( bIsIndefiniteTiming )
320 nFill = AnimationFill::FREEZE;
325 return nFill;
328 void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
330 Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
331 if( xNodeSupplier.is() )
333 const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
334 if( xRootNode.is() )
336 processAfterEffectNodes( xRootNode );
337 exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
342 void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
346 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
347 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
348 while( xEnumeration->hasMoreElements() )
350 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
352 Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
353 if ( xEnumerationAccess2.is() )
355 Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
356 while( xEnumeration2->hasMoreElements() )
358 Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
360 Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
361 Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
362 while( xEnumeration3->hasMoreElements() )
364 Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
366 Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
367 Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
368 while( xEnumeration4->hasMoreElements() )
370 Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
372 switch( xChildNode3->getType() )
374 // found an after effect
375 case AnimationNodeType::SET:
376 case AnimationNodeType::ANIMATECOLOR:
378 Reference< XAnimationNode > xMaster;
380 const Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
381 const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
382 [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
384 if (p != aUserData.end())
385 p->Value >>= xMaster;
387 AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
388 maAfterEffectNodes.push_back( pAfterEffectNode );
390 break;
398 catch( Exception& )
400 TOOLS_WARN_EXCEPTION( "sd", "(@CL)AnimationExporter::processAfterEffectNodes()" );
404 bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
406 return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
407 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
410 bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
412 auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
413 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
414 if (aIter != maAfterEffectNodes.end())
416 xAfterEffectNode = (*aIter)->mxNode;
417 return true;
420 return false;
423 // check if this group only contain empty groups. this may happen when
424 // after effect nodes are not exported at their original position
425 bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
427 if( xNode.is() ) switch( xNode->getType() )
429 case AnimationNodeType::PAR :
430 case AnimationNodeType::SEQ :
431 case AnimationNodeType::ITERATE :
433 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
434 if( xEnumerationAccess.is() )
436 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
437 if( xEnumeration.is() )
439 while( xEnumeration->hasMoreElements() )
441 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
442 if( xChildNode.is() && !isEmptyNode( xChildNode ) )
443 return false;
448 break;
450 case AnimationNodeType::SET :
451 case AnimationNodeType::ANIMATECOLOR :
452 return isAfterEffectNode( xNode );
453 default:
454 return false;
457 return true;
460 void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
461 const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
463 auto xNode = xNode_in;
465 if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
466 return;
468 if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
469 return;
471 if( nContainerRecType == DFF_msofbtAnimGroup )
472 mnCurrentGroup++;
474 bool bTakeBackInteractiveSequenceTimingForChild = false;
475 sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
477 Reference< XAnimationNode > xAudioNode;
478 static sal_uInt32 nAudioGroup;
481 bool bSkipChildren = false;
482 EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
483 switch( xNode->getType() )
485 case AnimationNodeType::CUSTOM :
487 exportAnimNode( rStrm, xNode, nFillDefault );
488 exportAnimPropertySet( rStrm, xNode );
489 exportAnimEvent( rStrm, xNode );
490 exportAnimValue( rStrm, xNode, false );
492 break;
494 case AnimationNodeType::PAR :
496 exportAnimNode( rStrm, xNode, nFillDefault );
497 exportAnimPropertySet( rStrm, xNode );
498 sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
499 if ( bTakeBackInteractiveSequenceTiming )
500 nFlags |= 0x40;
501 exportAnimEvent( rStrm, xNode, nFlags );
502 exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
504 break;
506 case AnimationNodeType::SEQ :
508 exportAnimNode( rStrm, xNode, nFillDefault );
509 sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
510 sal_Int32 nFlags = 12;
511 if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
513 nFlags |= 0x20;
514 bTakeBackInteractiveSequenceTimingForChild = true;
516 exportAnimAction( rStrm, xNode );
517 exportAnimEvent( rStrm, xNode, nFlags );
518 exportAnimValue( rStrm, xNode, false );
520 break;
522 case AnimationNodeType::ITERATE :
525 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
526 AnimationNode aAnim;
527 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
528 aAnim.mnNodeType = 1;
529 // attribute Restart
530 switch( xNode->getRestart() )
532 default:
533 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
534 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
535 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
536 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
538 // attribute Fill
539 switch( xNode->getFill() )
541 default:
542 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
543 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
544 case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
545 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
546 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
548 WriteAnimationNode( rStrm, aAnim );
550 exportIterate( rStrm, xNode );
551 exportAnimPropertySet( rStrm, xNode );
552 exportAnimEvent( rStrm, xNode );
553 exportAnimValue( rStrm, xNode, false );
555 break;
557 case AnimationNodeType::ANIMATE :
559 exportAnimNode( rStrm, xNode, nFillDefault );
560 exportAnimPropertySet( rStrm, xNode );
561 exportAnimEvent( rStrm, xNode );
562 exportAnimValue( rStrm, xNode, false );
563 exportAnimate( rStrm, xNode );
565 break;
567 case AnimationNodeType::SET :
569 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
570 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
572 exportAnimNode( rStrm, xNode, nFillDefault );
573 exportAnimPropertySet( rStrm, xNode );
574 exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
575 exportAnimEvent( rStrm, xNode );
576 exportAnimValue( rStrm, xNode, false );
578 else
580 bSkipChildren = true;
583 break;
585 case AnimationNodeType::ANIMATEMOTION :
587 exportAnimNode( rStrm, xNode, nFillDefault );
588 exportAnimPropertySet( rStrm, xNode );
589 exportAnimateMotion( rStrm, xNode );
590 exportAnimEvent( rStrm, xNode );
591 exportAnimValue( rStrm, xNode, false );
593 break;
595 case AnimationNodeType::ANIMATECOLOR :
597 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
598 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
600 if( bIsAfterEffectNode )
601 xNode = createAfterEffectNodeClone( xNode );
603 exportAnimNode( rStrm, xNode, nFillDefault );
604 exportAnimPropertySet( rStrm, xNode );
605 exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
606 exportAnimEvent( rStrm, xNode );
607 exportAnimValue( rStrm, xNode, false );
609 else
611 bSkipChildren = true;
614 break;
616 case AnimationNodeType::ANIMATETRANSFORM :
618 exportAnimNode( rStrm, xNode, nFillDefault );
619 exportAnimPropertySet( rStrm, xNode );
620 exportAnimateTransform( rStrm, xNode );
621 exportAnimEvent( rStrm, xNode );
622 exportAnimValue( rStrm, xNode, false );
624 break;
626 case AnimationNodeType::TRANSITIONFILTER :
628 exportAnimNode( rStrm, xNode, nFillDefault );
629 exportAnimPropertySet( rStrm, xNode );
630 exportAnimEvent( rStrm, xNode );
631 exportAnimValue( rStrm, xNode, false );
632 exportTransitionFilter( rStrm, xNode );
634 break;
636 case AnimationNodeType::AUDIO : // #i58428#
638 exportAnimNode( rStrm, xNode, nFillDefault );
639 exportAnimPropertySet( rStrm, xNode );
641 Reference< XAudio > xAudio( xNode, UNO_QUERY );
642 if( xAudio.is() )
644 Any aAny( xAudio->getSource() );
645 OUString aURL;
647 if ( ( aAny >>= aURL) && !aURL.isEmpty() )
649 sal_Int32 nU1 = 2;
650 sal_Int32 nTrigger = 3;
651 sal_Int32 nU3 = nAudioGroup;
652 sal_Int32 nBegin = 0;
654 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 );
656 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
657 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
660 nU1 = 1;
661 nTrigger = 0xb;
662 nU3 = 0;
664 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
666 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
667 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
670 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
672 sal_uInt32 const nRefMode = 3;
673 sal_uInt32 const nRefType = 2;
674 sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
675 sal_Int32 const begin = -1;
676 sal_Int32 const end = -1;
678 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
679 rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
683 exportAnimValue( rStrm, xNode, false );
685 break;
687 if( !bSkipChildren )
689 // export after effect node if one exists for this node
690 Reference< XAnimationNode > xAfterEffectNode;
691 if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
693 exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
696 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
697 if( xEnumerationAccess.is() )
699 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
700 if( xEnumeration.is() )
702 while( xEnumeration->hasMoreElements() )
704 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
705 if( xChildNode.is() )
707 if ( xChildNode->getType() == AnimationNodeType::AUDIO )
709 xAudioNode = std::move(xChildNode);
710 nAudioGroup = mnCurrentGroup;
712 else
713 exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
720 if ( xAudioNode.is() )
721 exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
723 if( xNode->getType() == AnimationNodeType::ITERATE )
724 aTarget = Any();
727 Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
731 Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
732 Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
734 Any aEmpty;
735 xCloneNode->setBegin( aEmpty );
737 return xCloneNode;
739 catch( Exception& )
741 OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
743 return xNode;
746 bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
748 // trying to get the nodetype
749 const Sequence< NamedValue > aUserData = xNode->getUserData();
750 for( const NamedValue& rProp : aUserData )
752 if ( rProp.Name == "node-type" )
754 if ( rProp.Value >>= nType )
755 return true;
759 return false;
762 void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
763 const sal_Int16 nFillDefault )
765 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
766 AnimationNode aAnim;
768 // attribute Restart
769 switch( xNode->getRestart() )
771 default:
772 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
773 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
774 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
775 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
778 switch( nFillDefault )
780 default:
781 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
782 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
783 case AnimationFill::FREEZE :
784 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
785 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
787 // attribute Duration
788 double fDuration = 0.0;
789 css::animations::Timing eTiming;
790 if ( xNode->getDuration() >>= eTiming )
792 if ( eTiming == Timing_INDEFINITE )
793 aAnim.mnDuration = -1;
795 else if ( xNode->getDuration() >>= fDuration )
797 aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
799 else
800 aAnim.mnDuration = -1;
802 // NodeType, NodeGroup
803 aAnim.mnNodeType = 1;
804 aAnim.mnGroupType = mso_Anim_GroupType_SEQ;
805 switch( xNode->getType() )
807 case AnimationNodeType::PAR :
808 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
809 [[fallthrough]];
810 case AnimationNodeType::SEQ :
812 sal_Int16 nType = 0;
813 if( GetNodeType( xNode, nType ) )
814 switch( nType )
816 case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
817 case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
820 break;
822 case AnimationNodeType::ANIMATE :
823 case AnimationNodeType::SET :
825 case AnimationNodeType::CUSTOM :
826 case AnimationNodeType::ITERATE :
827 case AnimationNodeType::ANIMATEMOTION :
828 case AnimationNodeType::ANIMATECOLOR :
829 case AnimationNodeType::ANIMATETRANSFORM :
831 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
832 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
834 break;
836 case AnimationNodeType::AUDIO :
838 aAnim.mnGroupType = mso_Anim_GroupType_MEDIA;
839 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
841 break;
843 case AnimationNodeType::TRANSITIONFILTER :
845 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
846 aAnim.mnNodeType = mso_Anim_Behaviour_FILTER;
848 break;
851 WriteAnimationNode( rStrm, aAnim );
854 void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
856 // storing user data into pAny, to allow direct access later
857 memset( pAny, 0, nLen );
858 if ( !rUserData.hasElements() )
859 return;
861 for( const NamedValue& rProp : rUserData )
863 if ( rProp.Name == "node-type" )
865 pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
867 else if ( rProp.Name == "preset-class" )
869 pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
871 else if ( rProp.Name == "preset-id" )
873 pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
875 else if ( rProp.Name == "preset-sub-type" )
877 pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
879 else if ( rProp.Name == "master-element" )
881 pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
886 sal_uInt32 AnimationExporter::GetPresetID( std::u16string_view aPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
888 sal_uInt32 nPresetId = 0;
889 bPresetId = false;
891 if ( o3tl::starts_with(aPreset, u"ppt_") )
893 size_t nLast = aPreset.rfind( '_' );
894 if ( ( nLast != std::u16string_view::npos ) && ( ( nLast + 1 ) < aPreset.size() ) )
896 std::u16string_view aNumber( aPreset.substr( nLast + 1 ) );
897 nPresetId = o3tl::toUInt32(aNumber);
898 bPresetId = true;
901 else
903 const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
904 while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !o3tl::equalsAscii(aPreset, p->mpStrPresetId )) )
905 p++;
907 if( p->mpStrPresetId )
909 nPresetId = p->mnPresetId;
910 bPresetId = true;
914 return nPresetId;
917 sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
919 sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
921 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
923 Reference< XAnimationNode > xMaster;
925 Any aMasterRel, aOverride, aRunTimeContext;
927 // storing user data into pAny, to allow direct access later
928 const Sequence< NamedValue > aUserData = xNode->getUserData();
929 const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
930 GetUserData( aUserData, pAny, sizeof( pAny ) );
932 if( pAny[ DFF_ANIM_AFTEREFFECT ] )
933 ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
935 // calculate master-rel
936 if( xMaster.is() )
938 sal_Int32 nMasterRel = 2;
939 if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
940 nMasterRel = 0;
942 aMasterRel <<= nMasterRel;
944 pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
946 aOverride <<= sal_Int32(1);
947 pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
949 aRunTimeContext <<= sal_Int32(1);
950 pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
953 // the order is important
954 if ( pAny[ DFF_ANIM_NODE_TYPE ] )
956 if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
958 sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
959 switch( nNodeType )
961 case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
962 case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
963 case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
964 case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
965 case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
966 case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
968 exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
971 sal_uInt32 nPresetId = 0;
972 sal_uInt32 nPresetSubType = 0;
973 sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
974 sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
975 bool bPresetClass, bPresetId, bPresetSubType;
976 bPresetId = bPresetClass = bPresetSubType = false;
978 if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
980 if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
982 sal_uInt8 nPPTPresetClass;
983 switch( nAPIPresetClass )
985 case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
986 case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
987 case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
988 case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
989 case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
990 case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
991 default :
992 nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
994 nPresetClass = nPPTPresetClass;
995 bPresetClass = true;
998 if ( pAny[ DFF_ANIM_PRESET_ID ] )
1000 OUString sPreset;
1001 if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
1002 nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
1005 if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
1007 OUString sPresetSubType;
1008 if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
1010 nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
1011 bPresetSubType = true;
1014 if ( bPresetId )
1015 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
1016 if ( bPresetSubType )
1017 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
1018 if ( bPresetClass )
1019 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
1021 if ( pAny[ DFF_ANIM_ID ] )
1023 // TODO DFF_ANIM_ID
1026 if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
1028 bool bAfterEffect = false;
1029 if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
1030 exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
1033 if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
1035 sal_Int32 nRunTimeContext = 0;
1036 if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
1037 exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
1039 if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
1041 // TODO DFF_ANIM_ID
1044 if( !xMaster.is() )
1046 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
1047 if( xColor.is() )
1050 bool bDirection = !xColor->getDirection();
1051 exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
1055 if ( pAny[ DFF_ANIM_OVERRIDE ] )
1057 sal_Int32 nOverride = 0;
1058 if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
1059 exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
1062 if ( pAny[ DFF_ANIM_MASTERREL ] )
1064 sal_Int32 nMasterRel = 0;
1065 if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
1066 exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
1069 /* todo
1070 Reference< XAudio > xAudio( xNode, UNO_QUERY );
1071 if( xAudio.is() )
1073 sal_Int16 nEndAfterSlide = 0;
1074 nEndAfterSlide = xAudio->getEndAfterSlide();
1075 exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
1078 Reference< XAnimate > xAnim( xNode, UNO_QUERY );
1079 if( xAnim.is() )
1081 // TODO: DFF_ANIM_TIMEFILTER
1083 if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
1085 // TODO DFF_ANIM_EVENT_FILTER
1087 if ( pAny[ DFF_ANIM_VOLUME ] )
1089 // TODO DFF_ANIM_VOLUME
1091 return nNodeType;
1094 bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
1096 bool bRet = false;
1097 if ( rAny.hasValue() )
1099 switch( rAny.getValueTypeClass() )
1101 case css::uno::TypeClass_UNSIGNED_SHORT :
1102 case css::uno::TypeClass_SHORT :
1103 case css::uno::TypeClass_UNSIGNED_LONG :
1104 case css::uno::TypeClass_LONG :
1106 sal_Int32 nVal = 0;
1107 if ( rAny >>= nVal )
1109 exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
1110 bRet = true;
1113 break;
1115 case css::uno::TypeClass_DOUBLE :
1117 double fVal = 0.0;
1118 if ( rAny >>= fVal )
1120 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1121 bRet = true;
1124 break;
1125 case css::uno::TypeClass_FLOAT :
1127 float fVal = 0.0;
1128 if ( rAny >>= fVal )
1130 if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
1132 OUString aNumber( OUString::number( fVal ) );
1133 exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
1135 else
1137 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1138 bRet = true;
1142 break;
1143 case css::uno::TypeClass_STRING :
1145 OUString aStr;
1146 if ( rAny >>= aStr )
1148 exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
1149 bRet = true;
1152 break;
1153 default:
1154 break;
1157 return bRet;
1159 void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
1161 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1162 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
1163 OUString aStr( rVal );
1164 if ( eTranslateMode != TRANSLATE_NONE )
1165 ImplTranslateAttribute( aStr, eTranslateMode );
1166 writeZString( rStrm, aStr );
1169 void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
1171 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1172 float fFloat = static_cast<float>(rVal);
1173 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
1174 .WriteFloat( fFloat );
1177 void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
1179 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1180 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
1181 .WriteUInt32( nVal );
1184 void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
1186 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1187 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
1188 .WriteUChar( nVal );
1191 void AnimationExporter::writeZString( SvStream& rStrm, std::u16string_view aVal )
1193 for ( size_t i = 0; i < aVal.size(); i++ )
1194 rStrm.WriteUInt16( aVal[ i ] );
1195 rStrm.WriteUInt16( 0 );
1198 void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1200 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
1202 sal_Int32 const nConcurrent = 1;
1203 sal_Int32 const nNextAction = 1;
1204 sal_Int32 nEndSync = 0;
1205 sal_Int32 const nU4 = 0;
1206 sal_Int32 const nU5 = 3;
1208 sal_Int16 nAnimationEndSync = 0;
1209 if ( xNode->getEndSync() >>= nAnimationEndSync )
1211 if ( nAnimationEndSync == AnimationEndSync::ALL )
1212 nEndSync = 1;
1214 rStrm.WriteInt32( nConcurrent )
1215 .WriteInt32( nNextAction )
1216 .WriteInt32( nEndSync )
1217 .WriteInt32( nU4 )
1218 .WriteInt32( nU5 );
1222 // nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
1223 // nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
1224 // nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
1225 void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
1227 sal_uInt16 i;
1228 for ( i = 0; i < 4; i++ )
1230 sal_Int32 nU1 = 0;
1231 sal_Int32 nTrigger = 0;
1232 sal_Int32 nU3 = 0;
1233 sal_Int32 nBegin = 0;
1235 bool bCreateEvent = false;
1236 Any aSource;
1238 switch( i )
1240 case 0 :
1241 case 1 :
1243 Any aAny;
1244 Event aEvent;
1245 css::animations::Timing eTiming;
1246 if ( i == 0 )
1248 if ( nFlags & 0x20 )
1250 // taking the first child
1251 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
1252 Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
1253 if ( xE->hasMoreElements() )
1255 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
1256 aAny = xClickNode->getBegin();
1259 else if ( nFlags & 0x40 )
1261 // begin has to be replaced with void, so don't do anything
1263 else
1265 aAny = xNode->getBegin();
1266 if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
1268 if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
1270 eTiming = Timing_INDEFINITE;
1271 aAny <<= eTiming;
1276 else
1277 aAny = xNode->getEnd();
1279 double fTiming = 0.0;
1280 if ( aAny >>= aEvent )
1282 bCreateEvent = true;
1283 switch( aEvent.Trigger )
1285 case EventTrigger::NONE : nTrigger = 0; break;
1286 case EventTrigger::ON_BEGIN : nTrigger = 1; break;
1287 case EventTrigger::ON_END : nTrigger = 2; break;
1288 case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
1289 case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
1290 case EventTrigger::ON_CLICK : nTrigger = 5; break;
1291 case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
1292 case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
1293 case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
1294 case EventTrigger::ON_NEXT : nTrigger = 9; break;
1295 case EventTrigger::ON_PREV : nTrigger = 10; break;
1296 case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
1298 if ( aEvent.Offset.hasValue() )
1300 if ( aEvent.Offset >>= eTiming )
1302 if ( eTiming == Timing_INDEFINITE )
1303 nBegin = -1;
1305 else if ( aEvent.Offset >>= fTiming )
1306 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1308 aSource = aEvent.Source;
1310 else if ( aAny >>= eTiming )
1312 bCreateEvent = true;
1313 if ( eTiming == Timing_INDEFINITE )
1314 nBegin = -1;
1316 else if ( aAny >>= fTiming )
1318 bCreateEvent = true;
1319 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1322 break;
1324 case 2 :
1326 if ( nFlags & ( 1 << i ) )
1328 bCreateEvent = true;
1329 nU1 = 1;
1330 nTrigger = 9;
1333 break;
1334 case 3 :
1336 if ( nFlags & ( 1 << i ) )
1338 bCreateEvent = true;
1339 nU1 = 1;
1340 nTrigger = 10;
1343 break;
1345 if ( bCreateEvent )
1347 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
1349 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
1350 rStrm.WriteInt32( nU1 )
1351 .WriteInt32( nTrigger )
1352 .WriteInt32( nU3 )
1353 .WriteInt32( nBegin );
1355 exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
1360 Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, std::u16string_view rAttributeName )
1362 OUString aDest;
1363 if ( rAttributeName == u"X"
1364 || rAttributeName == u"Y"
1365 || rAttributeName == u"Width"
1366 || rAttributeName == u"Height"
1369 OUString aStr;
1370 if ( rSourceValue >>= aStr )
1372 ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
1373 aDest += aStr;
1376 else if ( rAttributeName == u"Rotate" // "r" or "style.rotation" ?
1377 || rAttributeName == u"Opacity"
1378 || rAttributeName == u"CharHeight"
1379 || rAttributeName == u"SkewX"
1382 double fNumber = 0.0;
1383 if ( rSourceValue >>= fNumber )
1384 aDest += OUString::number( fNumber );
1386 else if ( rAttributeName == u"Color"
1387 || rAttributeName == u"FillColor" // "Fillcolor" or "FillColor" ?
1388 || rAttributeName == u"LineColor"
1389 || rAttributeName == u"CharColor"
1392 sal_Int32 nColor = 0;
1393 Sequence< double > aHSL( 3 );
1394 OUString aP( u","_ustr );
1395 if ( rSourceValue >>= aHSL )
1397 aDest += "hsl("
1398 + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
1399 + aP
1400 + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
1401 + aP
1402 + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
1403 + ")";
1405 else if ( rSourceValue >>= nColor )
1407 aDest += "rgb("
1408 + OUString::number( static_cast<sal_Int8>(nColor) )
1409 + aP
1410 + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
1411 + aP
1412 + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
1413 + ")";
1416 else if ( rAttributeName == u"FillStyle" )
1418 css::drawing::FillStyle eFillStyle;
1419 if ( rSourceValue >>= eFillStyle )
1421 if ( eFillStyle == css::drawing::FillStyle_NONE )
1422 aDest += "none"; // ?
1423 else
1424 aDest += "solid";
1427 else if (rAttributeName == u"FillOn")
1429 bool bFillOn;
1430 if ( rSourceValue >>= bFillOn )
1432 if ( bFillOn )
1433 aDest += "true";
1434 else
1435 aDest += "false";
1438 else if ( rAttributeName == u"LineStyle" )
1440 css::drawing::LineStyle eLineStyle;
1441 if ( rSourceValue >>= eLineStyle )
1443 if ( eLineStyle == css::drawing::LineStyle_NONE )
1444 aDest += "false";
1445 else
1446 aDest += "true";
1449 else if ( rAttributeName == u"CharWeight" )
1451 float fFontWeight = 0.0;
1452 if ( rSourceValue >>= fFontWeight )
1454 if ( fFontWeight == css::awt::FontWeight::BOLD )
1455 aDest += "bold";
1456 else
1457 aDest += "normal";
1460 else if ( rAttributeName == u"CharUnderline" )
1462 sal_Int16 nFontUnderline = 0;
1463 if ( rSourceValue >>= nFontUnderline )
1465 if ( nFontUnderline == css::awt::FontUnderline::NONE )
1466 aDest += "false";
1467 else
1468 aDest += "true";
1471 else if ( rAttributeName == u"CharPosture" )
1473 css::awt::FontSlant eFontSlant;
1474 if ( rSourceValue >>= eFontSlant )
1476 if ( eFontSlant == css::awt::FontSlant_ITALIC )
1477 aDest += "italic";
1478 else
1479 aDest += "normal"; // ?
1482 else if ( rAttributeName == u"Visibility" )
1484 bool bVisible = true;
1485 if ( rSourceValue >>= bVisible )
1487 if ( bVisible )
1488 aDest += "visible";
1489 else
1490 aDest += "hidden";
1493 Any aRet;
1494 if ( !aDest.isEmpty() )
1495 aRet <<= aDest;
1496 else
1497 aRet = rSourceValue;
1498 return aRet;
1501 void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
1503 Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
1504 if( !xSet.is() )
1505 return;
1507 EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
1509 EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
1510 sal_uInt32 const nId1 = 1; // ??
1511 sal_uInt32 const nId2 = 1; // ??
1512 rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
1514 Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
1515 if ( aConvertedValue.hasValue() )
1516 exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
1517 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
1520 sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( std::u16string_view rAttributeName )
1522 sal_uInt32 nValueType = 0;
1524 struct Entry
1526 const char* pName;
1527 sal_uInt8 nType;
1529 static const Entry lcl_attributeMap[] =
1531 { "charcolor", 2 },
1532 { "charfontname", 0 },
1533 { "charheight", 1 },
1534 { "charposture", 0 },
1535 // TODO(Q1): This should prolly be changed in PPT import
1536 // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
1537 { "charrotation", 1 },
1538 { "charunderline", 0 },
1539 { "charweight", 0 },
1540 { "color", 2 },
1541 { "dimcolor", 2 },
1542 { "fillcolor", 2 },
1543 { "fillstyle", 0 },
1544 { "height", 1 },
1545 { "linecolor", 2 },
1546 { "linestyle", 0 },
1547 { "opacity", 0 },
1548 { "rotate", 1 },
1549 { "skewx", 1 },
1550 { "skewy", 1 },
1551 { "visibility", 1 },
1552 { "width", 1 },
1553 { "x", 1 },
1554 { "y", 1 },
1555 { nullptr, 0 }
1557 const Entry* pPtr = &lcl_attributeMap[ 0 ];
1558 while( pPtr->pName )
1560 if ( o3tl::equalsIgnoreAsciiCase( rAttributeName, pPtr->pName ) )
1562 nValueType = pPtr->nType;
1563 break;
1565 pPtr++;
1567 DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
1568 return nValueType;
1571 void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1573 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1574 if ( !xAnimate.is() )
1575 return;
1577 Any aBy ( xAnimate->getBy() );
1578 Any aFrom( xAnimate->getFrom() );
1579 Any aTo ( xAnimate->getTo() );
1581 EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
1583 EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
1584 sal_uInt32 nBits = 0x38;
1585 sal_Int16 nTmp = xAnimate->getCalcMode();
1586 sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
1587 sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
1589 if ( aBy.hasValue() )
1590 nBits |= 1;
1591 if ( aFrom.hasValue() )
1592 nBits |= 2;
1593 if ( aTo.hasValue() )
1594 nBits |= 4;
1596 rStrm.WriteUInt32( nCalcMode )
1597 .WriteUInt32( nBits )
1598 .WriteUInt32( nValueType );
1600 if ( aBy.hasValue() )
1601 exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1602 if ( aFrom.hasValue() )
1603 exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1604 if ( aTo.hasValue() )
1605 exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1607 exportAnimateKeyPoints( rStrm, xAnimate );
1608 exportAnimateTarget( rStrm, xNode );
1611 void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
1613 EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
1614 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1615 if ( !xAnimate.is() )
1616 return;
1619 EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
1620 // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
1621 // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
1622 // nAccumulate 0 = none, 1 = always
1623 // nTransformType 0: "property" else "image"
1624 sal_uInt32 nBits = 0;
1625 sal_uInt32 nAdditive = 0;
1626 sal_uInt32 nAccumulate = 0;
1627 sal_uInt32 const nTransformType = 0;
1628 if ( xAnimate.is() )
1630 if ( !xAnimate->getAttributeName().isEmpty() )
1631 nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
1632 sal_Int16 nAdditiveMode = xAnimate->getAdditive();
1633 if ( nAdditiveMode != AnimationAdditiveMode::BASE )
1635 nBits |= 1;
1636 switch( nAdditiveMode )
1638 case AnimationAdditiveMode::SUM : nAdditive = 1; break;
1639 case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
1640 case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
1641 case AnimationAdditiveMode::NONE : nAdditive = 4; break;
1644 if ( xAnimate->getAccumulate() )
1646 nBits |= 2;
1647 nAccumulate = 1;
1650 rStrm.WriteUInt32( nBits )
1651 .WriteUInt32( nAdditive )
1652 .WriteUInt32( nAccumulate )
1653 .WriteUInt32( nTransformType );
1655 if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
1657 EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
1658 OUString aAttributeName( xAnimate->getAttributeName() );
1659 if ( nForceAttributeNames )
1661 if( nForceAttributeNames == 1 )
1663 aAttributeName = "r";
1666 sal_Int32 nIndex = 0;
1669 OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
1670 exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE );
1672 while ( nIndex >= 0 );
1675 if( nAfterEffectType != AFTEREFFECT_NONE )
1677 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
1678 exportAnimPropertyuInt32( rStrm, 6, 1 );
1679 if( nAfterEffectType == AFTEREFFECT_COLOR )
1681 exportAnimPropertyuInt32( rStrm, 4, 0 );
1682 exportAnimPropertyuInt32( rStrm, 5, 0 );
1685 exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
1688 Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
1690 Reference< XShape > xShape;
1691 rAny >>= xShape;
1693 rParagraphTarget = false;
1695 if( xShape.is() )
1696 return xShape;
1698 ParagraphTarget aParaTarget;
1699 if( rAny >>= aParaTarget )
1700 xShape = aParaTarget.Shape;
1701 if ( !xShape.is() )
1702 return xShape;
1704 // now calculating the character range for the paragraph
1705 sal_Int16 nParagraph = aParaTarget.Paragraph;
1706 Reference< XSimpleText > xText( xShape, UNO_QUERY );
1707 if ( !xText.is() )
1708 return xShape;
1710 rParagraphTarget = true;
1711 Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
1712 if ( !xTextParagraphEnumerationAccess.is() )
1713 return xShape;
1715 Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
1716 if ( !xTextParagraphEnumeration.is() )
1717 return xShape;
1719 sal_Int16 nCurrentParagraph;
1720 rBegin = rEnd = nCurrentParagraph = 0;
1721 while ( xTextParagraphEnumeration->hasMoreElements() )
1723 Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
1724 if ( xTextRange.is() )
1726 OUString aParaText( xTextRange->getString() );
1727 sal_Int32 nLength = aParaText.getLength() + 1;
1728 rEnd += nLength;
1729 if ( nCurrentParagraph == nParagraph )
1730 break;
1731 nCurrentParagraph++;
1732 rBegin += nLength;
1736 return xShape;
1739 void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
1741 sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
1742 sal_Int32 begin = -1;
1743 sal_Int32 end = -1;
1744 bool bParagraphTarget;
1746 Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
1748 if( bParagraphTarget )
1749 nRefMode = 2;
1751 if ( !(xShape.is() || bCreate2b01Atom) )
1752 return;
1754 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
1755 if ( xShape.is() )
1757 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
1759 sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
1760 sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
1762 rStrm.WriteUInt32( nRefMode )
1763 .WriteUInt32( nRefType )
1764 .WriteUInt32( nRefId )
1765 .WriteInt32( begin )
1766 .WriteInt32( end );
1768 if ( bCreate2b01Atom )
1770 EscherExAtom a2b01Atom( rStrm, 0x2b01 );
1771 rStrm.WriteUInt32( 1 ); // ?
1775 void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
1777 Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
1778 Sequence< Any > aValues( xAnimate->getValues() );
1779 OUString aFormula( xAnimate->getFormula() );
1780 if ( !aKeyTimes.hasElements() )
1781 return;
1783 EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
1784 sal_Int32 i;
1785 for ( i = 0; i < aKeyTimes.getLength(); i++ )
1788 EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
1789 sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
1790 rStrm.WriteInt32( nKeyTime );
1792 Any aAny[ 2 ];
1793 if ( aValues[ i ].hasValue() )
1795 ValuePair aPair;
1796 if ( aValues[ i ] >>= aPair )
1798 aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
1799 aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
1801 else
1803 aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
1805 if ( !i && !aFormula.isEmpty() )
1807 ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE );
1808 aAny[ 1 ] <<= aFormula;
1810 exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
1811 exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
1816 void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
1818 Any aAny;
1819 // repeat count (0)
1820 double fRepeat = 0.0;
1821 float fRepeatCount = 0.0;
1822 css::animations::Timing eTiming;
1823 aAny = xNode->getRepeatCount();
1824 if ( aAny >>= eTiming )
1826 if ( eTiming == Timing_INDEFINITE )
1827 fRepeatCount = (float(3.40282346638528860e+38));
1829 else if ( aAny >>= fRepeat )
1830 fRepeatCount = static_cast<float>(fRepeat);
1831 if ( fRepeatCount != 0.0 )
1833 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1834 sal_uInt32 const nType = 0;
1835 rStrm.WriteUInt32( nType )
1836 .WriteFloat( fRepeatCount );
1838 // accelerate (3)
1839 float fAccelerate = static_cast<float>(xNode->getAcceleration());
1840 if ( bExportAlways || ( fAccelerate != 0.0 ) )
1842 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1843 sal_uInt32 const nType = 3;
1844 rStrm.WriteUInt32( nType )
1845 .WriteFloat( fAccelerate );
1848 // decelerate (4)
1849 float fDecelerate = static_cast<float>(xNode->getDecelerate());
1850 if ( bExportAlways || ( fDecelerate != 0.0 ) )
1852 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1853 sal_uInt32 const nType = 4;
1854 rStrm.WriteUInt32( nType )
1855 .WriteFloat( fDecelerate );
1858 // autoreverse (5)
1859 bool bAutoReverse = xNode->getAutoReverse();
1860 if ( bExportAlways || bAutoReverse )
1862 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1863 sal_uInt32 const nType = 5;
1864 sal_uInt32 nVal = bAutoReverse ? 1 : 0;
1865 rStrm.WriteUInt32( nType )
1866 .WriteUInt32( nVal );
1870 void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1872 Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
1873 if ( !xFilter.is() )
1874 return;
1876 EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
1878 EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
1879 sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
1880 // bit 1 -> use nTransition
1882 sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
1883 rStrm.WriteUInt32( nBits )
1884 .WriteUInt32( nTransition );
1886 const char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
1887 if ( pFilter )
1889 const OUString aStr( OUString::createFromAscii( pFilter ) );
1890 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1892 exportAnimateTarget( rStrm, xNode );
1895 void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1897 Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
1898 if ( !xMotion.is() )
1899 return;
1901 EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
1903 { //SJ: Ignored from import filter
1904 EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
1905 sal_uInt32 const nBits = 0x98;
1906 sal_uInt32 const nOrigin = 0x2;
1907 float const fByX = 100.0; // nBits&1
1908 float const fByY = 100.0; // nBits&1
1909 float const fFromX = 0.0; // nBits&2
1910 float const fFromY = 0.0; // nBits&2
1911 float const fToX = 100.0; // nBits&4
1912 float const fToY = 100.0; // nBits&4
1913 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
1916 OUString aStr;
1917 if ( xMotion->getPath() >>= aStr )
1919 if ( !aStr.isEmpty() )
1920 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1922 exportAnimateTarget( rStrm, xNode );
1926 void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1928 Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
1929 if ( !xTransform.is() )
1930 return;
1932 if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
1934 EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
1936 EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
1937 sal_uInt32 nBits = 0;
1938 sal_uInt32 const nZoomContents = 1;
1939 float fByX = 100.0;
1940 float fByY = 100.0;
1941 float fFromX = 0.0;
1942 float fFromY = 0.0;
1943 float fToX = 100.0;
1944 float fToY = 100.0;
1946 double fX = 0.0, fY = 0.0;
1947 ValuePair aPair;
1948 if ( xTransform->getBy() >>= aPair )
1950 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1952 nBits |= 1;
1953 fByX = static_cast<float>( fX * 100 );
1954 fByY = static_cast<float>( fY * 100 );
1957 if ( xTransform->getFrom() >>= aPair )
1959 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1961 nBits |= 2;
1962 fFromX = static_cast<float>( fX * 100 );
1963 fFromY = static_cast<float>( fY * 100 );
1966 if( xTransform->getTo() >>= aPair )
1968 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1970 nBits |= 4;
1971 fToX = static_cast<float>( fX * 100 );
1972 fToY = static_cast<float>( fY * 100 );
1976 // TODO: ZoomContents:
1977 //if( nBits & 8 )
1978 //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
1980 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
1982 exportAnimateTarget( rStrm, xNode );
1984 else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
1986 EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation );
1988 EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
1989 sal_uInt32 nBits = 0;
1990 sal_uInt32 const nU1 = 0;
1991 float fBy = 360.0;
1992 float fFrom = 0.0;
1993 float fTo = 360.0;
1995 double fVal = 0.0;
1996 if ( xTransform->getBy() >>= fVal )
1998 nBits |= 1;
1999 fBy = static_cast<float>(fVal);
2001 if ( xTransform->getFrom() >>= fVal )
2003 nBits |= 2;
2004 fFrom = static_cast<float>(fVal);
2006 if ( xTransform->getTo() >>= fVal )
2008 nBits |= 4;
2009 fTo = static_cast<float>(fVal);
2011 rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
2013 exportAnimateTarget( rStrm, xNode, 1 );
2017 bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
2019 bool bIsColor = true;
2021 rMode = 0;
2022 if ( nColorSpace == AnimationColorSpace::HSL )
2023 rMode = 1;
2025 sal_Int32 nColor = 0;
2026 Sequence< double > aHSL( 3 );
2027 if ( rAny >>= nColor ) // RGB color
2029 rA = static_cast<sal_uInt8>( nColor >> 16 );
2030 rB = static_cast<sal_uInt8>( nColor >> 8 );
2031 rC = static_cast<sal_uInt8>(nColor);
2033 else if ( rAny >>= aHSL ) // HSL
2035 rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
2036 rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
2037 rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
2039 else
2040 bIsColor = false;
2041 return bIsColor;
2044 void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
2046 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
2047 if ( !xColor.is() )
2048 return;
2050 EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor );
2052 EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
2053 sal_uInt32 nBits = 8;
2055 sal_Int32 nByMode, nByA, nByB, nByC;
2056 nByMode = nByA = nByB = nByC = 0;
2058 sal_Int32 nFromMode, nFromA, nFromB, nFromC;
2059 nFromMode = nFromA = nFromB = nFromC = 0;
2061 sal_Int32 nToMode, nToA, nToB, nToC;
2062 nToMode = nToA = nToB = nToC = 0;
2064 sal_Int16 nColorSpace = xColor->getColorInterpolation();
2066 Any aAny( xColor->getBy() );
2067 if ( aAny.hasValue() )
2069 if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
2070 nBits |= 0x11;
2072 aAny = xColor->getFrom();
2073 if ( aAny.hasValue() )
2075 if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
2076 nBits |= 0x12;
2078 aAny = xColor->getTo();
2079 if ( aAny.hasValue() )
2081 if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
2082 nBits |= 0x14;
2084 rStrm .WriteUInt32( nBits )
2085 .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
2086 .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
2087 .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
2089 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
2092 void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
2094 Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
2095 if ( !xIterate.is() )
2096 return;
2098 EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
2100 float fInterval = 10.0;
2101 sal_Int32 nTextUnitEffect = 0;
2102 sal_Int32 const nU1 = 1;
2103 sal_Int32 const nU2 = 1;
2104 sal_Int32 const nU3 = 0xe;
2106 sal_Int16 nIterateType = xIterate->getIterateType();
2107 switch( nIterateType )
2109 case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
2110 case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
2113 fInterval = static_cast<float>(xIterate->getIterateInterval());
2115 // convert interval from absolute to percentage
2116 double fDuration = 0.0;
2118 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
2119 if( xEnumerationAccess.is() )
2121 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
2122 if( xEnumeration.is() )
2124 while( xEnumeration->hasMoreElements() )
2126 Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
2127 if( xChildNode.is() )
2129 double fChildBegin = 0.0;
2130 double fChildDuration = 0.0;
2131 xChildNode->getBegin() >>= fChildBegin;
2132 xChildNode->getDuration() >>= fChildDuration;
2134 fChildDuration += fChildBegin;
2135 if( fChildDuration > fDuration )
2136 fDuration = fChildDuration;
2142 if( fDuration )
2143 fInterval = static_cast<float>(100.0 * fInterval / fDuration);
2145 rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
2146 aTarget = xIterate->getTarget();
2149 } // namespace ppt;
2151 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */