nss: upgrade to release 3.73
[LibreOffice.git] / sd / source / filter / eppt / pptexanimations.cxx
blobeaa346b809ed27daa5f403358ad54945424329a7
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>
62 #include <algorithm>
64 using ::com::sun::star::uno::Any;
65 using ::com::sun::star::util::XCloneable;
66 using ::com::sun::star::uno::Reference;
67 using ::com::sun::star::uno::UNO_QUERY;
68 using ::com::sun::star::uno::UNO_QUERY_THROW;
69 using ::com::sun::star::uno::Sequence;
70 using ::com::sun::star::uno::Exception;
71 using ::com::sun::star::beans::NamedValue;
72 using ::com::sun::star::container::XEnumerationAccess;
73 using ::com::sun::star::container::XEnumeration;
75 using namespace ::com::sun::star::text;
76 using namespace ::com::sun::star::drawing;
77 using namespace ::com::sun::star::animations;
78 using namespace ::com::sun::star::presentation;
80 namespace ppt
83 static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
85 if ( eTranslateMode == TRANSLATE_NONE )
86 return;
88 if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
90 const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
91 while( p->mpAPIName )
93 if( rString.equalsAscii( p->mpAPIName ) )
94 break;
95 p++;
97 if( p->mpMSName )
99 if ( eTranslateMode & TRANSLATE_VALUE )
101 rString = "#";
102 rString += OUString::createFromAscii( p->mpMSName );
104 else
105 rString = OUString::createFromAscii( p->mpMSName );
108 else if ( eTranslateMode & TRANSLATE_MEASURE )
110 const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
111 const char* pSource[] = { "x", "y", "width", "height", nullptr };
112 sal_Int32 nIndex = 0;
114 const char** ps = pSource;
115 const char** pd = pDest;
117 while( *ps )
119 const OUString aSearch( OUString::createFromAscii( *ps ) );
120 while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
122 sal_Int32 nLength = aSearch.getLength();
123 if( nIndex && ( rString[nIndex-1] == '#' ) )
125 nIndex--;
126 nLength++;
129 const OUString aNew( OUString::createFromAscii( *pd ) );
130 rString = rString.replaceAt( nIndex, nLength, aNew );
131 nIndex += aNew.getLength();
133 ps++;
134 pd++;
139 sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, const OUString& rPresetSubType )
141 sal_uInt32 nPresetSubType = 0;
142 bool bTranslated = false;
144 if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
146 if ( nPresetId != 21 )
148 switch( nPresetId )
150 case 5 :
152 if ( rPresetSubType == "downward" )
154 nPresetSubType = 5;
155 bTranslated = true;
157 else if ( rPresetSubType == "across" )
159 nPresetSubType = 10;
160 bTranslated = true;
163 break;
164 case 17 :
166 if ( rPresetSubType == "across" )
168 nPresetSubType = 10;
169 bTranslated = true;
172 break;
173 case 18 :
175 if ( rPresetSubType == "right-to-top" )
177 nPresetSubType = 3;
178 bTranslated = true;
180 else if ( rPresetSubType == "right-to-bottom" )
182 nPresetSubType = 6;
183 bTranslated = true;
185 else if ( rPresetSubType == "left-to-top" )
187 nPresetSubType = 9;
188 bTranslated = true;
190 else if ( rPresetSubType == "left-to-bottom" )
192 nPresetSubType = 12;
193 bTranslated = true;
196 break;
199 if ( !bTranslated )
201 const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
202 while( p->mpStrSubType )
204 if ( rPresetSubType.equalsAscii( p->mpStrSubType ) )
206 nPresetSubType = p->mnID;
207 bTranslated = true;
208 break;
210 p++;
214 if ( !bTranslated )
215 nPresetSubType = rPresetSubType.toUInt32();
216 return nPresetSubType;
219 const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
221 const char* pRet = nullptr;
222 int nFit = 0;
224 const oox::ppt::transition* p = oox::ppt::transition::getList();
225 while( p->mpName )
227 int nF = 0;
228 if ( nType == p->mnType )
229 nF += 4;
230 if ( nSubType == p->mnSubType )
231 nF += 2;
232 if ( bDirection == p->mbDirection )
233 nF += 1;
234 if ( nF > nFit )
236 pRet = p->mpName;
237 nFit = nF;
239 if ( nFit == 7 ) // maximum
240 break;
241 p++;
243 return pRet;
246 SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
248 rOut.WriteInt32( rNode.mnU1 );
249 rOut.WriteInt32( rNode.mnRestart );
250 rOut.WriteInt32( rNode.mnGroupType );
251 rOut.WriteInt32( rNode.mnFill );
252 rOut.WriteInt32( rNode.mnU3 );
253 rOut.WriteInt32( rNode.mnU4 );
254 rOut.WriteInt32( rNode.mnDuration );
255 rOut.WriteInt32( rNode.mnNodeType );
257 return rOut;
260 AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
261 mrSolverContainer ( rSolverContainer ),
262 mrExSoundCollection ( rExSoundCollection ),
263 mnCurrentGroup(0)
267 sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
269 sal_Int16 nFill = xNode->getFill();
270 //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
271 //#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.
272 if ((xNode->getType() == AnimationNodeType::ANIMATE)
273 ||(xNode->getType() == AnimationNodeType::SET)
274 ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
276 if ( nFill == AnimationFill::DEFAULT )
277 return nFill;
280 if ( nFill == AnimationFill::DEFAULT )
282 nFill = nFillDefault;
284 if( nFill == AnimationFill::AUTO )
286 nFill = AnimationFill::REMOVE;
287 bool bIsIndefiniteTiming = true;
288 Any aAny = xNode->getDuration();
289 if( aAny.hasValue() )
291 Timing eTiming;
292 if( aAny >>= eTiming )
293 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
295 if ( bIsIndefiniteTiming )
297 aAny = xNode->getEnd();
298 if( aAny.hasValue() )
300 Timing eTiming;
301 if( aAny >>= eTiming )
302 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
304 if ( bIsIndefiniteTiming )
306 if ( !xNode->getRepeatCount().hasValue() )
308 aAny = xNode->getRepeatDuration();
309 if( aAny.hasValue() )
311 Timing eTiming;
312 if( aAny >>= eTiming )
313 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
315 if ( bIsIndefiniteTiming )
316 nFill = AnimationFill::FREEZE;
321 return nFill;
324 void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
326 Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
327 if( xNodeSupplier.is() )
329 const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
330 if( xRootNode.is() )
332 processAfterEffectNodes( xRootNode );
333 exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
338 void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
342 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
343 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
344 while( xEnumeration->hasMoreElements() )
346 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
348 Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
349 if ( xEnumerationAccess2.is() )
351 Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
352 while( xEnumeration2->hasMoreElements() )
354 Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
356 Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
357 Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
358 while( xEnumeration3->hasMoreElements() )
360 Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
362 Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
363 Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
364 while( xEnumeration4->hasMoreElements() )
366 Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
368 switch( xChildNode3->getType() )
370 // found an after effect
371 case AnimationNodeType::SET:
372 case AnimationNodeType::ANIMATECOLOR:
374 Reference< XAnimationNode > xMaster;
376 Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
377 const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
378 [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
380 if (p != aUserData.end())
381 p->Value >>= xMaster;
383 AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
384 maAfterEffectNodes.push_back( pAfterEffectNode );
386 break;
394 catch( Exception& )
396 OSL_FAIL( "(@CL)AnimationExporter::processAfterEffectNodes(), exception caught!" );
400 bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
402 return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
403 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
406 bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
408 auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
409 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
410 if (aIter != maAfterEffectNodes.end())
412 xAfterEffectNode = (*aIter)->mxNode;
413 return true;
416 return false;
419 // check if this group only contain empty groups. this may happen when
420 // after effect nodes are not exported at their original position
421 bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
423 if( xNode.is() ) switch( xNode->getType() )
425 case AnimationNodeType::PAR :
426 case AnimationNodeType::SEQ :
427 case AnimationNodeType::ITERATE :
429 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
430 if( xEnumerationAccess.is() )
432 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
433 if( xEnumeration.is() )
435 while( xEnumeration->hasMoreElements() )
437 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
438 if( xChildNode.is() && !isEmptyNode( xChildNode ) )
439 return false;
444 break;
446 case AnimationNodeType::SET :
447 case AnimationNodeType::ANIMATECOLOR :
448 return isAfterEffectNode( xNode );
449 default:
450 return false;
453 return true;
456 void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
457 const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
459 auto xNode = xNode_in;
461 if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
462 return;
464 if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
465 return;
467 if( nContainerRecType == DFF_msofbtAnimGroup )
468 mnCurrentGroup++;
470 bool bTakeBackInteractiveSequenceTimingForChild = false;
471 sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
473 Reference< XAnimationNode > xAudioNode;
474 static sal_uInt32 nAudioGroup;
477 bool bSkipChildren = false;
478 EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
479 switch( xNode->getType() )
481 case AnimationNodeType::CUSTOM :
483 exportAnimNode( rStrm, xNode, nFillDefault );
484 exportAnimPropertySet( rStrm, xNode );
485 exportAnimEvent( rStrm, xNode );
486 exportAnimValue( rStrm, xNode, false );
488 break;
490 case AnimationNodeType::PAR :
492 exportAnimNode( rStrm, xNode, nFillDefault );
493 exportAnimPropertySet( rStrm, xNode );
494 sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
495 if ( bTakeBackInteractiveSequenceTiming )
496 nFlags |= 0x40;
497 exportAnimEvent( rStrm, xNode, nFlags );
498 exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
500 break;
502 case AnimationNodeType::SEQ :
504 exportAnimNode( rStrm, xNode, nFillDefault );
505 sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
506 sal_Int32 nFlags = 12;
507 if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
509 nFlags |= 0x20;
510 bTakeBackInteractiveSequenceTimingForChild = true;
512 exportAnimAction( rStrm, xNode );
513 exportAnimEvent( rStrm, xNode, nFlags );
514 exportAnimValue( rStrm, xNode, false );
516 break;
518 case AnimationNodeType::ITERATE :
521 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
522 AnimationNode aAnim;
523 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
524 aAnim.mnNodeType = 1;
525 // attribute Restart
526 switch( xNode->getRestart() )
528 default:
529 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
530 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
531 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
532 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
534 // attribute Fill
535 switch( xNode->getFill() )
537 default:
538 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
539 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
540 case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
541 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
542 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
544 WriteAnimationNode( rStrm, aAnim );
546 exportIterate( rStrm, xNode );
547 exportAnimPropertySet( rStrm, xNode );
548 exportAnimEvent( rStrm, xNode );
549 exportAnimValue( rStrm, xNode, false );
551 break;
553 case AnimationNodeType::ANIMATE :
555 exportAnimNode( rStrm, xNode, nFillDefault );
556 exportAnimPropertySet( rStrm, xNode );
557 exportAnimEvent( rStrm, xNode );
558 exportAnimValue( rStrm, xNode, false );
559 exportAnimate( rStrm, xNode );
561 break;
563 case AnimationNodeType::SET :
565 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
566 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
568 exportAnimNode( rStrm, xNode, nFillDefault );
569 exportAnimPropertySet( rStrm, xNode );
570 exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
571 exportAnimEvent( rStrm, xNode );
572 exportAnimValue( rStrm, xNode, false );
574 else
576 bSkipChildren = true;
579 break;
581 case AnimationNodeType::ANIMATEMOTION :
583 exportAnimNode( rStrm, xNode, nFillDefault );
584 exportAnimPropertySet( rStrm, xNode );
585 exportAnimateMotion( rStrm, xNode );
586 exportAnimEvent( rStrm, xNode );
587 exportAnimValue( rStrm, xNode, false );
589 break;
591 case AnimationNodeType::ANIMATECOLOR :
593 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
594 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
596 if( bIsAfterEffectNode )
597 xNode = createAfterEffectNodeClone( xNode );
599 exportAnimNode( rStrm, xNode, nFillDefault );
600 exportAnimPropertySet( rStrm, xNode );
601 exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
602 exportAnimEvent( rStrm, xNode );
603 exportAnimValue( rStrm, xNode, false );
605 else
607 bSkipChildren = true;
610 break;
612 case AnimationNodeType::ANIMATETRANSFORM :
614 exportAnimNode( rStrm, xNode, nFillDefault );
615 exportAnimPropertySet( rStrm, xNode );
616 exportAnimateTransform( rStrm, xNode );
617 exportAnimEvent( rStrm, xNode );
618 exportAnimValue( rStrm, xNode, false );
620 break;
622 case AnimationNodeType::TRANSITIONFILTER :
624 exportAnimNode( rStrm, xNode, nFillDefault );
625 exportAnimPropertySet( rStrm, xNode );
626 exportAnimEvent( rStrm, xNode );
627 exportAnimValue( rStrm, xNode, false );
628 exportTransitionFilter( rStrm, xNode );
630 break;
632 case AnimationNodeType::AUDIO : // #i58428#
634 exportAnimNode( rStrm, xNode, nFillDefault );
635 exportAnimPropertySet( rStrm, xNode );
637 Reference< XAudio > xAudio( xNode, UNO_QUERY );
638 if( xAudio.is() )
640 Any aAny( xAudio->getSource() );
641 OUString aURL;
643 if ( ( aAny >>= aURL) && !aURL.isEmpty() )
645 sal_Int32 nU1 = 2;
646 sal_Int32 nTrigger = 3;
647 sal_Int32 nU3 = nAudioGroup;
648 sal_Int32 nBegin = 0;
650 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 );
652 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
653 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
656 nU1 = 1;
657 nTrigger = 0xb;
658 nU3 = 0;
660 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
662 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
663 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
666 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
668 sal_uInt32 const nRefMode = 3;
669 sal_uInt32 const nRefType = 2;
670 sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
671 sal_Int32 const begin = -1;
672 sal_Int32 const end = -1;
674 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
675 rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
679 exportAnimValue( rStrm, xNode, false );
681 break;
683 if( !bSkipChildren )
685 // export after effect node if one exists for this node
686 Reference< XAnimationNode > xAfterEffectNode;
687 if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
689 exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
692 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
693 if( xEnumerationAccess.is() )
695 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
696 if( xEnumeration.is() )
698 while( xEnumeration->hasMoreElements() )
700 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
701 if( xChildNode.is() )
703 if ( xChildNode->getType() == AnimationNodeType::AUDIO )
705 xAudioNode = xChildNode;
706 nAudioGroup = mnCurrentGroup;
708 else
709 exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
716 if ( xAudioNode.is() )
717 exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
719 if( xNode->getType() == AnimationNodeType::ITERATE )
720 aTarget = Any();
723 Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
727 Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
728 Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
730 Any aEmpty;
731 xCloneNode->setBegin( aEmpty );
733 return xCloneNode;
735 catch( Exception& )
737 OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
739 return xNode;
742 bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
744 // trying to get the nodetype
745 const Sequence< NamedValue > aUserData = xNode->getUserData();
746 for( const NamedValue& rProp : aUserData )
748 if ( rProp.Name == "node-type" )
750 if ( rProp.Value >>= nType )
751 return true;
755 return false;
758 void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
759 const sal_Int16 nFillDefault )
761 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
762 AnimationNode aAnim;
764 // attribute Restart
765 switch( xNode->getRestart() )
767 default:
768 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
769 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
770 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
771 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
774 switch( nFillDefault )
776 default:
777 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
778 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
779 case AnimationFill::FREEZE :
780 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
781 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
783 // attribute Duration
784 double fDuration = 0.0;
785 css::animations::Timing eTiming;
786 if ( xNode->getDuration() >>= eTiming )
788 if ( eTiming == Timing_INDEFINITE )
789 aAnim.mnDuration = -1;
791 else if ( xNode->getDuration() >>= fDuration )
793 aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
795 else
796 aAnim.mnDuration = -1;
798 // NodeType, NodeGroup
799 aAnim.mnNodeType = 1;
800 aAnim.mnGroupType = mso_Anim_GroupType_SEQ;
801 switch( xNode->getType() )
803 case AnimationNodeType::PAR :
804 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
805 [[fallthrough]];
806 case AnimationNodeType::SEQ :
808 sal_Int16 nType = 0;
809 if( GetNodeType( xNode, nType ) )
810 switch( nType )
812 case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
813 case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
816 break;
818 case AnimationNodeType::ANIMATE :
819 case AnimationNodeType::SET :
821 case AnimationNodeType::CUSTOM :
822 case AnimationNodeType::ITERATE :
823 case AnimationNodeType::ANIMATEMOTION :
824 case AnimationNodeType::ANIMATECOLOR :
825 case AnimationNodeType::ANIMATETRANSFORM :
827 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
828 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
830 break;
832 case AnimationNodeType::AUDIO :
834 aAnim.mnGroupType = mso_Anim_GroupType_MEDIA;
835 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
837 break;
839 case AnimationNodeType::TRANSITIONFILTER :
841 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
842 aAnim.mnNodeType = mso_Anim_Behaviour_FILTER;
844 break;
847 WriteAnimationNode( rStrm, aAnim );
850 void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
852 // storing user data into pAny, to allow direct access later
853 memset( pAny, 0, nLen );
854 if ( !rUserData.hasElements() )
855 return;
857 for( const NamedValue& rProp : rUserData )
859 if ( rProp.Name == "node-type" )
861 pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
863 else if ( rProp.Name == "preset-class" )
865 pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
867 else if ( rProp.Name == "preset-id" )
869 pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
871 else if ( rProp.Name == "preset-sub-type" )
873 pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
875 else if ( rProp.Name == "master-element" )
877 pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
882 sal_uInt32 AnimationExporter::GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
884 sal_uInt32 nPresetId = 0;
885 bPresetId = false;
887 if ( rPreset.match("ppt_", 0) )
889 sal_Int32 nLast = rPreset.lastIndexOf( '_' );
890 if ( ( nLast != -1 ) && ( ( nLast + 1 ) < rPreset.getLength() ) )
892 OUString aNumber( rPreset.copy( nLast + 1 ) );
893 nPresetId = aNumber.toUInt32();
894 bPresetId = true;
897 else
899 const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
900 while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !rPreset.equalsAscii( p->mpStrPresetId )) )
901 p++;
903 if( p->mpStrPresetId )
905 nPresetId = p->mnPresetId;
906 bPresetId = true;
910 return nPresetId;
913 sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
915 sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
917 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
919 Reference< XAnimationNode > xMaster;
921 Any aMasterRel, aOverride, aRunTimeContext;
923 // storing user data into pAny, to allow direct access later
924 const Sequence< NamedValue > aUserData = xNode->getUserData();
925 const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
926 GetUserData( aUserData, pAny, sizeof( pAny ) );
928 if( pAny[ DFF_ANIM_AFTEREFFECT ] )
929 ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
931 // calculate master-rel
932 if( xMaster.is() )
934 sal_Int32 nMasterRel = 2;
935 if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
936 nMasterRel = 0;
938 aMasterRel <<= nMasterRel;
940 pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
942 aOverride <<= sal_Int32(1);
943 pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
945 aRunTimeContext <<= sal_Int32(1);
946 pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
949 // the order is important
950 if ( pAny[ DFF_ANIM_NODE_TYPE ] )
952 if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
954 sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
955 switch( nNodeType )
957 case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
958 case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
959 case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
960 case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
961 case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
962 case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
964 exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
967 sal_uInt32 nPresetId = 0;
968 sal_uInt32 nPresetSubType = 0;
969 sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
970 sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
971 bool bPresetClass, bPresetId, bPresetSubType;
972 bPresetId = bPresetClass = bPresetSubType = false;
974 if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
976 if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
978 sal_uInt8 nPPTPresetClass;
979 switch( nAPIPresetClass )
981 case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
982 case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
983 case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
984 case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
985 case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
986 case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
987 default :
988 nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
990 nPresetClass = nPPTPresetClass;
991 bPresetClass = true;
994 if ( pAny[ DFF_ANIM_PRESET_ID ] )
996 OUString sPreset;
997 if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
998 nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
1001 if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
1003 OUString sPresetSubType;
1004 if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
1006 nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
1007 bPresetSubType = true;
1010 if ( bPresetId )
1011 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
1012 if ( bPresetSubType )
1013 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
1014 if ( bPresetClass )
1015 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
1017 if ( pAny[ DFF_ANIM_ID ] )
1019 // TODO DFF_ANIM_ID
1022 if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
1024 bool bAfterEffect = false;
1025 if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
1026 exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
1029 if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
1031 sal_Int32 nRunTimeContext = 0;
1032 if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
1033 exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
1035 if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
1037 // TODO DFF_ANIM_ID
1040 if( !xMaster.is() )
1042 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
1043 if( xColor.is() )
1046 bool bDirection = !xColor->getDirection();
1047 exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
1051 if ( pAny[ DFF_ANIM_OVERRIDE ] )
1053 sal_Int32 nOverride = 0;
1054 if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
1055 exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
1058 if ( pAny[ DFF_ANIM_MASTERREL ] )
1060 sal_Int32 nMasterRel = 0;
1061 if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
1062 exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
1065 /* todo
1066 Reference< XAudio > xAudio( xNode, UNO_QUERY );
1067 if( xAudio.is() )
1069 sal_Int16 nEndAfterSlide = 0;
1070 nEndAfterSlide = xAudio->getEndAfterSlide();
1071 exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
1074 Reference< XAnimate > xAnim( xNode, UNO_QUERY );
1075 if( xAnim.is() )
1077 // TODO: DFF_ANIM_TIMEFILTER
1079 if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
1081 // TODO DFF_ANIM_EVENT_FILTER
1083 if ( pAny[ DFF_ANIM_VOLUME ] )
1085 // TODO DFF_ANIM_VOLUME
1087 return nNodeType;
1090 bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
1092 bool bRet = false;
1093 if ( rAny.hasValue() )
1095 switch( rAny.getValueType().getTypeClass() )
1097 case css::uno::TypeClass_UNSIGNED_SHORT :
1098 case css::uno::TypeClass_SHORT :
1099 case css::uno::TypeClass_UNSIGNED_LONG :
1100 case css::uno::TypeClass_LONG :
1102 sal_Int32 nVal = 0;
1103 if ( rAny >>= nVal )
1105 exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
1106 bRet = true;
1109 break;
1111 case css::uno::TypeClass_DOUBLE :
1113 double fVal = 0.0;
1114 if ( rAny >>= fVal )
1116 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1117 bRet = true;
1120 break;
1121 case css::uno::TypeClass_FLOAT :
1123 float fVal = 0.0;
1124 if ( rAny >>= fVal )
1126 if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
1128 OUString aNumber( OUString::number( fVal ) );
1129 exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
1131 else
1133 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1134 bRet = true;
1138 break;
1139 case css::uno::TypeClass_STRING :
1141 OUString aStr;
1142 if ( rAny >>= aStr )
1144 exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
1145 bRet = true;
1148 break;
1149 default:
1150 break;
1153 return bRet;
1155 void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
1157 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1158 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
1159 OUString aStr( rVal );
1160 if ( eTranslateMode != TRANSLATE_NONE )
1161 ImplTranslateAttribute( aStr, eTranslateMode );
1162 writeZString( rStrm, aStr );
1165 void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
1167 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1168 float fFloat = static_cast<float>(rVal);
1169 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
1170 .WriteFloat( fFloat );
1173 void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
1175 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1176 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
1177 .WriteUInt32( nVal );
1180 void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
1182 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1183 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
1184 .WriteUChar( nVal );
1187 void AnimationExporter::writeZString( SvStream& rStrm, const OUString& rVal )
1189 sal_Int32 i;
1190 for ( i = 0; i < rVal.getLength(); i++ )
1191 rStrm.WriteUInt16( rVal[ i ] );
1192 rStrm.WriteUInt16( 0 );
1195 void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1197 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
1199 sal_Int32 const nConcurrent = 1;
1200 sal_Int32 const nNextAction = 1;
1201 sal_Int32 nEndSync = 0;
1202 sal_Int32 const nU4 = 0;
1203 sal_Int32 const nU5 = 3;
1205 sal_Int16 nAnimationEndSync = 0;
1206 if ( xNode->getEndSync() >>= nAnimationEndSync )
1208 if ( nAnimationEndSync == AnimationEndSync::ALL )
1209 nEndSync = 1;
1211 rStrm.WriteInt32( nConcurrent )
1212 .WriteInt32( nNextAction )
1213 .WriteInt32( nEndSync )
1214 .WriteInt32( nU4 )
1215 .WriteInt32( nU5 );
1219 // nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
1220 // nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
1221 // nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
1222 void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
1224 sal_uInt16 i;
1225 for ( i = 0; i < 4; i++ )
1227 sal_Int32 nU1 = 0;
1228 sal_Int32 nTrigger = 0;
1229 sal_Int32 nU3 = 0;
1230 sal_Int32 nBegin = 0;
1232 bool bCreateEvent = false;
1233 Any aSource;
1235 switch( i )
1237 case 0 :
1238 case 1 :
1240 Any aAny;
1241 Event aEvent;
1242 css::animations::Timing eTiming;
1243 if ( i == 0 )
1245 if ( nFlags & 0x20 )
1247 // taking the first child
1248 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
1249 Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
1250 if ( xE->hasMoreElements() )
1252 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
1253 aAny = xClickNode->getBegin();
1256 else if ( nFlags & 0x40 )
1258 // begin has to be replaced with void, so don't do anything
1260 else
1262 aAny = xNode->getBegin();
1263 if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
1265 if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
1267 eTiming = Timing_INDEFINITE;
1268 aAny <<= eTiming;
1273 else
1274 aAny = xNode->getEnd();
1276 double fTiming = 0.0;
1277 if ( aAny >>= aEvent )
1279 bCreateEvent = true;
1280 switch( aEvent.Trigger )
1282 case EventTrigger::NONE : nTrigger = 0; break;
1283 case EventTrigger::ON_BEGIN : nTrigger = 1; break;
1284 case EventTrigger::ON_END : nTrigger = 2; break;
1285 case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
1286 case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
1287 case EventTrigger::ON_CLICK : nTrigger = 5; break;
1288 case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
1289 case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
1290 case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
1291 case EventTrigger::ON_NEXT : nTrigger = 9; break;
1292 case EventTrigger::ON_PREV : nTrigger = 10; break;
1293 case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
1295 if ( aEvent.Offset.hasValue() )
1297 if ( aEvent.Offset >>= eTiming )
1299 if ( eTiming == Timing_INDEFINITE )
1300 nBegin = -1;
1302 else if ( aEvent.Offset >>= fTiming )
1303 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1305 aSource = aEvent.Source;
1307 else if ( aAny >>= eTiming )
1309 bCreateEvent = true;
1310 if ( eTiming == Timing_INDEFINITE )
1311 nBegin = -1;
1313 else if ( aAny >>= fTiming )
1315 bCreateEvent = true;
1316 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1319 break;
1321 case 2 :
1323 if ( nFlags & ( 1 << i ) )
1325 bCreateEvent = true;
1326 nU1 = 1;
1327 nTrigger = 9;
1330 break;
1331 case 3 :
1333 if ( nFlags & ( 1 << i ) )
1335 bCreateEvent = true;
1336 nU1 = 1;
1337 nTrigger = 10;
1340 break;
1342 if ( bCreateEvent )
1344 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
1346 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
1347 rStrm.WriteInt32( nU1 )
1348 .WriteInt32( nTrigger )
1349 .WriteInt32( nU3 )
1350 .WriteInt32( nBegin );
1352 exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
1357 Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, const OUString& rAttributeName )
1359 OUString aDest;
1360 if ( rAttributeName == "X"
1361 || rAttributeName == "Y"
1362 || rAttributeName == "Width"
1363 || rAttributeName == "Height"
1366 OUString aStr;
1367 if ( rSourceValue >>= aStr )
1369 ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
1370 aDest += aStr;
1373 else if ( rAttributeName == "Rotate" // "r" or "style.rotation" ?
1374 || rAttributeName == "Opacity"
1375 || rAttributeName == "CharHeight"
1376 || rAttributeName == "SkewX"
1379 double fNumber = 0.0;
1380 if ( rSourceValue >>= fNumber )
1381 aDest += OUString::number( fNumber );
1383 else if ( rAttributeName == "Color"
1384 || rAttributeName == "FillColor" // "Fillcolor" or "FillColor" ?
1385 || rAttributeName == "LineColor"
1386 || rAttributeName == "CharColor"
1389 sal_Int32 nColor = 0;
1390 Sequence< double > aHSL( 3 );
1391 OUString aP( "," );
1392 if ( rSourceValue >>= aHSL )
1394 aDest += "hsl("
1395 + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
1396 + aP
1397 + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
1398 + aP
1399 + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
1400 + ")";
1402 else if ( rSourceValue >>= nColor )
1404 aDest += "rgb("
1405 + OUString::number( static_cast<sal_Int8>(nColor) )
1406 + aP
1407 + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
1408 + aP
1409 + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
1410 + ")";
1413 else if ( rAttributeName == "FillStyle" )
1415 css::drawing::FillStyle eFillStyle;
1416 if ( rSourceValue >>= eFillStyle )
1418 if ( eFillStyle == css::drawing::FillStyle_NONE )
1419 aDest += "none"; // ?
1420 else
1421 aDest += "solid";
1424 else if (rAttributeName == "FillOn")
1426 bool bFillOn;
1427 if ( rSourceValue >>= bFillOn )
1429 if ( bFillOn )
1430 aDest += "true";
1431 else
1432 aDest += "false";
1435 else if ( rAttributeName == "LineStyle" )
1437 css::drawing::LineStyle eLineStyle;
1438 if ( rSourceValue >>= eLineStyle )
1440 if ( eLineStyle == css::drawing::LineStyle_NONE )
1441 aDest += "false";
1442 else
1443 aDest += "true";
1446 else if ( rAttributeName == "CharWeight" )
1448 float fFontWeight = 0.0;
1449 if ( rSourceValue >>= fFontWeight )
1451 if ( fFontWeight == css::awt::FontWeight::BOLD )
1452 aDest += "bold";
1453 else
1454 aDest += "normal";
1457 else if ( rAttributeName == "CharUnderline" )
1459 sal_Int16 nFontUnderline = 0;
1460 if ( rSourceValue >>= nFontUnderline )
1462 if ( nFontUnderline == css::awt::FontUnderline::NONE )
1463 aDest += "false";
1464 else
1465 aDest += "true";
1468 else if ( rAttributeName == "CharPosture" )
1470 css::awt::FontSlant eFontSlant;
1471 if ( rSourceValue >>= eFontSlant )
1473 if ( eFontSlant == css::awt::FontSlant_ITALIC )
1474 aDest += "italic";
1475 else
1476 aDest += "normal"; // ?
1479 else if ( rAttributeName == "Visibility" )
1481 bool bVisible = true;
1482 if ( rSourceValue >>= bVisible )
1484 if ( bVisible )
1485 aDest += "visible";
1486 else
1487 aDest += "hidden";
1490 Any aRet;
1491 if ( !aDest.isEmpty() )
1492 aRet <<= aDest;
1493 else
1494 aRet = rSourceValue;
1495 return aRet;
1498 void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
1500 Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
1501 if( !xSet.is() )
1502 return;
1504 EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
1506 EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
1507 sal_uInt32 const nId1 = 1; // ??
1508 sal_uInt32 const nId2 = 1; // ??
1509 rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
1511 Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
1512 if ( aConvertedValue.hasValue() )
1513 exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
1514 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
1517 sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( const OUString& rAttributeName )
1519 sal_uInt32 nValueType = 0;
1521 struct Entry
1523 const char* pName;
1524 sal_uInt8 nType;
1526 static const Entry lcl_attributeMap[] =
1528 { "charcolor", 2 },
1529 { "charfontname", 0 },
1530 { "charheight", 1 },
1531 { "charposture", 0 },
1532 // TODO(Q1): This should prolly be changed in PPT import
1533 // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
1534 { "charrotation", 1 },
1535 { "charunderline", 0 },
1536 { "charweight", 0 },
1537 { "color", 2 },
1538 { "dimcolor", 2 },
1539 { "fillcolor", 2 },
1540 { "fillstyle", 0 },
1541 { "height", 1 },
1542 { "linecolor", 2 },
1543 { "linestyle", 0 },
1544 { "opacity", 0 },
1545 { "rotate", 1 },
1546 { "skewx", 1 },
1547 { "skewy", 1 },
1548 { "visibility", 1 },
1549 { "width", 1 },
1550 { "x", 1 },
1551 { "y", 1 },
1552 { nullptr, 0 }
1554 const Entry* pPtr = &lcl_attributeMap[ 0 ];
1555 while( pPtr->pName )
1557 if ( rAttributeName.equalsIgnoreAsciiCaseAscii( pPtr->pName ) )
1559 nValueType = pPtr->nType;
1560 break;
1562 pPtr++;
1564 DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
1565 return nValueType;
1568 void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1570 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1571 if ( !xAnimate.is() )
1572 return;
1574 Any aBy ( xAnimate->getBy() );
1575 Any aFrom( xAnimate->getFrom() );
1576 Any aTo ( xAnimate->getTo() );
1578 EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
1580 EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
1581 sal_uInt32 nBits = 0x38;
1582 sal_Int16 nTmp = xAnimate->getCalcMode();
1583 sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
1584 sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
1586 if ( aBy.hasValue() )
1587 nBits |= 1;
1588 if ( aFrom.hasValue() )
1589 nBits |= 2;
1590 if ( aTo.hasValue() )
1591 nBits |= 4;
1593 rStrm.WriteUInt32( nCalcMode )
1594 .WriteUInt32( nBits )
1595 .WriteUInt32( nValueType );
1597 if ( aBy.hasValue() )
1598 exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1599 if ( aFrom.hasValue() )
1600 exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1601 if ( aTo.hasValue() )
1602 exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1604 exportAnimateKeyPoints( rStrm, xAnimate );
1605 exportAnimateTarget( rStrm, xNode );
1608 void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
1610 EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
1611 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1612 if ( !xAnimate.is() )
1613 return;
1616 EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
1617 // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
1618 // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
1619 // nAccumulate 0 = none, 1 = always
1620 // nTransformType 0: "property" else "image"
1621 sal_uInt32 nBits = 0;
1622 sal_uInt32 nAdditive = 0;
1623 sal_uInt32 nAccumulate = 0;
1624 sal_uInt32 const nTransformType = 0;
1625 if ( xAnimate.is() )
1627 if ( !xAnimate->getAttributeName().isEmpty() )
1628 nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
1629 sal_Int16 nAdditiveMode = xAnimate->getAdditive();
1630 if ( nAdditiveMode != AnimationAdditiveMode::BASE )
1632 nBits |= 1;
1633 switch( nAdditiveMode )
1635 case AnimationAdditiveMode::SUM : nAdditive = 1; break;
1636 case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
1637 case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
1638 case AnimationAdditiveMode::NONE : nAdditive = 4; break;
1641 if ( xAnimate->getAccumulate() )
1643 nBits |= 2;
1644 nAccumulate = 1;
1647 rStrm.WriteUInt32( nBits )
1648 .WriteUInt32( nAdditive )
1649 .WriteUInt32( nAccumulate )
1650 .WriteUInt32( nTransformType );
1652 if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
1654 EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
1655 OUString aAttributeName( xAnimate->getAttributeName() );
1656 if ( nForceAttributeNames )
1658 if( nForceAttributeNames == 1 )
1660 aAttributeName = "r";
1663 sal_Int32 nIndex = 0;
1666 OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
1667 exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE );
1669 while ( nIndex >= 0 );
1672 if( nAfterEffectType != AFTEREFFECT_NONE )
1674 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
1675 exportAnimPropertyuInt32( rStrm, 6, 1 );
1676 if( nAfterEffectType == AFTEREFFECT_COLOR )
1678 exportAnimPropertyuInt32( rStrm, 4, 0 );
1679 exportAnimPropertyuInt32( rStrm, 5, 0 );
1682 exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
1685 Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
1687 Reference< XShape > xShape;
1688 rAny >>= xShape;
1690 rParagraphTarget = false;
1692 if( !xShape.is() )
1694 ParagraphTarget aParaTarget;
1695 if( rAny >>= aParaTarget )
1696 xShape = aParaTarget.Shape;
1697 if ( xShape.is() )
1699 // now calculating the character range for the paragraph
1700 sal_Int16 nParagraph = aParaTarget.Paragraph;
1701 Reference< XSimpleText > xText( xShape, UNO_QUERY );
1702 if ( xText.is() )
1704 rParagraphTarget = true;
1705 Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
1706 if ( xTextParagraphEnumerationAccess.is() )
1708 Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
1709 if ( xTextParagraphEnumeration.is() )
1711 sal_Int16 nCurrentParagraph;
1712 rBegin = rEnd = nCurrentParagraph = 0;
1713 while ( xTextParagraphEnumeration->hasMoreElements() )
1715 Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
1716 if ( xTextRange.is() )
1718 OUString aParaText( xTextRange->getString() );
1719 sal_Int32 nLength = aParaText.getLength() + 1;
1720 rEnd += nLength;
1721 if ( nCurrentParagraph == nParagraph )
1722 break;
1723 nCurrentParagraph++;
1724 rBegin += nLength;
1733 return xShape;
1736 void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
1738 sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
1739 sal_Int32 begin = -1;
1740 sal_Int32 end = -1;
1741 bool bParagraphTarget;
1743 Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
1745 if( bParagraphTarget )
1746 nRefMode = 2;
1748 if ( !(xShape.is() || bCreate2b01Atom) )
1749 return;
1751 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
1752 if ( xShape.is() )
1754 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
1756 sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
1757 sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
1759 rStrm.WriteUInt32( nRefMode )
1760 .WriteUInt32( nRefType )
1761 .WriteUInt32( nRefId )
1762 .WriteInt32( begin )
1763 .WriteInt32( end );
1765 if ( bCreate2b01Atom )
1767 EscherExAtom a2b01Atom( rStrm, 0x2b01 );
1768 rStrm.WriteUInt32( 1 ); // ?
1772 void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
1774 Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
1775 Sequence< Any > aValues( xAnimate->getValues() );
1776 OUString aFormula( xAnimate->getFormula() );
1777 if ( !aKeyTimes.hasElements() )
1778 return;
1780 EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
1781 sal_Int32 i;
1782 for ( i = 0; i < aKeyTimes.getLength(); i++ )
1785 EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
1786 sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
1787 rStrm.WriteInt32( nKeyTime );
1789 Any aAny[ 2 ];
1790 if ( aValues[ i ].hasValue() )
1792 ValuePair aPair;
1793 if ( aValues[ i ] >>= aPair )
1795 aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
1796 aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
1798 else
1800 aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
1802 if ( !i && !aFormula.isEmpty() )
1804 ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE );
1805 aAny[ 1 ] <<= aFormula;
1807 exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
1808 exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
1813 void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
1815 Any aAny;
1816 // repeat count (0)
1817 double fRepeat = 0.0;
1818 float fRepeatCount = 0.0;
1819 css::animations::Timing eTiming;
1820 aAny = xNode->getRepeatCount();
1821 if ( aAny >>= eTiming )
1823 if ( eTiming == Timing_INDEFINITE )
1824 fRepeatCount = (float(3.40282346638528860e+38));
1826 else if ( aAny >>= fRepeat )
1827 fRepeatCount = static_cast<float>(fRepeat);
1828 if ( fRepeatCount != 0.0 )
1830 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1831 sal_uInt32 const nType = 0;
1832 rStrm.WriteUInt32( nType )
1833 .WriteFloat( fRepeatCount );
1835 // accelerate (3)
1836 float fAccelerate = static_cast<float>(xNode->getAcceleration());
1837 if ( bExportAlways || ( fAccelerate != 0.0 ) )
1839 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1840 sal_uInt32 const nType = 3;
1841 rStrm.WriteUInt32( nType )
1842 .WriteFloat( fAccelerate );
1845 // decelerate (4)
1846 float fDecelerate = static_cast<float>(xNode->getDecelerate());
1847 if ( bExportAlways || ( fDecelerate != 0.0 ) )
1849 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1850 sal_uInt32 const nType = 4;
1851 rStrm.WriteUInt32( nType )
1852 .WriteFloat( fDecelerate );
1855 // autoreverse (5)
1856 bool bAutoReverse = xNode->getAutoReverse();
1857 if ( bExportAlways || bAutoReverse )
1859 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1860 sal_uInt32 const nType = 5;
1861 sal_uInt32 nVal = bAutoReverse ? 1 : 0;
1862 rStrm.WriteUInt32( nType )
1863 .WriteUInt32( nVal );
1867 void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1869 Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
1870 if ( !xFilter.is() )
1871 return;
1873 EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
1875 EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
1876 sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
1877 // bit 1 -> use nTransition
1879 sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
1880 rStrm.WriteUInt32( nBits )
1881 .WriteUInt32( nTransition );
1883 const char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
1884 if ( pFilter )
1886 const OUString aStr( OUString::createFromAscii( pFilter ) );
1887 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1889 exportAnimateTarget( rStrm, xNode );
1892 void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1894 Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
1895 if ( !xMotion.is() )
1896 return;
1898 EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
1900 { //SJ: Ignored from import filter
1901 EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
1902 sal_uInt32 const nBits = 0x98;
1903 sal_uInt32 const nOrigin = 0x2;
1904 float const fByX = 100.0; // nBits&1
1905 float const fByY = 100.0; // nBits&1
1906 float const fFromX = 0.0; // nBits&2
1907 float const fFromY = 0.0; // nBits&2
1908 float const fToX = 100.0; // nBits&4
1909 float const fToY = 100.0; // nBits&4
1910 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
1913 OUString aStr;
1914 if ( xMotion->getPath() >>= aStr )
1916 if ( !aStr.isEmpty() )
1917 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1919 exportAnimateTarget( rStrm, xNode );
1923 void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1925 Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
1926 if ( !xTransform.is() )
1927 return;
1929 if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
1931 EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
1933 EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
1934 sal_uInt32 nBits = 0;
1935 sal_uInt32 const nZoomContents = 1;
1936 float fByX = 100.0;
1937 float fByY = 100.0;
1938 float fFromX = 0.0;
1939 float fFromY = 0.0;
1940 float fToX = 100.0;
1941 float fToY = 100.0;
1943 double fX = 0.0, fY = 0.0;
1944 ValuePair aPair;
1945 if ( xTransform->getBy() >>= aPair )
1947 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1949 nBits |= 1;
1950 fByX = static_cast<float>( fX * 100 );
1951 fByY = static_cast<float>( fY * 100 );
1954 if ( xTransform->getFrom() >>= aPair )
1956 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1958 nBits |= 2;
1959 fFromX = static_cast<float>( fX * 100 );
1960 fFromY = static_cast<float>( fY * 100 );
1963 if( xTransform->getTo() >>= aPair )
1965 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1967 nBits |= 4;
1968 fToX = static_cast<float>( fX * 100 );
1969 fToY = static_cast<float>( fY * 100 );
1973 // TODO: ZoomContents:
1974 //if( nBits & 8 )
1975 //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
1977 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
1979 exportAnimateTarget( rStrm, xNode );
1981 else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
1983 EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation );
1985 EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
1986 sal_uInt32 nBits = 0;
1987 sal_uInt32 const nU1 = 0;
1988 float fBy = 360.0;
1989 float fFrom = 0.0;
1990 float fTo = 360.0;
1992 double fVal = 0.0;
1993 if ( xTransform->getBy() >>= fVal )
1995 nBits |= 1;
1996 fBy = static_cast<float>(fVal);
1998 if ( xTransform->getFrom() >>= fVal )
2000 nBits |= 2;
2001 fFrom = static_cast<float>(fVal);
2003 if ( xTransform->getTo() >>= fVal )
2005 nBits |= 4;
2006 fTo = static_cast<float>(fVal);
2008 rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
2010 exportAnimateTarget( rStrm, xNode, 1 );
2014 bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
2016 bool bIsColor = true;
2018 rMode = 0;
2019 if ( nColorSpace == AnimationColorSpace::HSL )
2020 rMode = 1;
2022 sal_Int32 nColor = 0;
2023 Sequence< double > aHSL( 3 );
2024 if ( rAny >>= nColor ) // RGB color
2026 rA = static_cast<sal_uInt8>( nColor >> 16 );
2027 rB = static_cast<sal_uInt8>( nColor >> 8 );
2028 rC = static_cast<sal_uInt8>(nColor);
2030 else if ( rAny >>= aHSL ) // HSL
2032 rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
2033 rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
2034 rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
2036 else
2037 bIsColor = false;
2038 return bIsColor;
2041 void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
2043 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
2044 if ( !xColor.is() )
2045 return;
2047 EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor );
2049 EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
2050 sal_uInt32 nBits = 8;
2052 sal_Int32 nByMode, nByA, nByB, nByC;
2053 nByMode = nByA = nByB = nByC = 0;
2055 sal_Int32 nFromMode, nFromA, nFromB, nFromC;
2056 nFromMode = nFromA = nFromB = nFromC = 0;
2058 sal_Int32 nToMode, nToA, nToB, nToC;
2059 nToMode = nToA = nToB = nToC = 0;
2061 sal_Int16 nColorSpace = xColor->getColorInterpolation();
2063 Any aAny( xColor->getBy() );
2064 if ( aAny.hasValue() )
2066 if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
2067 nBits |= 0x11;
2069 aAny = xColor->getFrom();
2070 if ( aAny.hasValue() )
2072 if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
2073 nBits |= 0x12;
2075 aAny = xColor->getTo();
2076 if ( aAny.hasValue() )
2078 if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
2079 nBits |= 0x14;
2081 rStrm .WriteUInt32( nBits )
2082 .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
2083 .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
2084 .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
2086 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
2089 void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
2091 Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
2092 if ( !xIterate.is() )
2093 return;
2095 EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
2097 float fInterval = 10.0;
2098 sal_Int32 nTextUnitEffect = 0;
2099 sal_Int32 const nU1 = 1;
2100 sal_Int32 const nU2 = 1;
2101 sal_Int32 const nU3 = 0xe;
2103 sal_Int16 nIterateType = xIterate->getIterateType();
2104 switch( nIterateType )
2106 case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
2107 case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
2110 fInterval = static_cast<float>(xIterate->getIterateInterval());
2112 // convert interval from absolute to percentage
2113 double fDuration = 0.0;
2115 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
2116 if( xEnumerationAccess.is() )
2118 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
2119 if( xEnumeration.is() )
2121 while( xEnumeration->hasMoreElements() )
2123 Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
2124 if( xChildNode.is() )
2126 double fChildBegin = 0.0;
2127 double fChildDuration = 0.0;
2128 xChildNode->getBegin() >>= fChildBegin;
2129 xChildNode->getDuration() >>= fChildDuration;
2131 fChildDuration += fChildBegin;
2132 if( fChildDuration > fDuration )
2133 fDuration = fChildDuration;
2139 if( fDuration )
2140 fInterval = static_cast<float>(100.0 * fInterval / fDuration);
2142 rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
2143 aTarget = xIterate->getTarget();
2146 } // namespace ppt;
2148 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */