bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / filter / eppt / pptexanimations.cxx
blobe90e9e16efc2df67eaa8a5cc63c5ea76592766a0
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/awt/FontWeight.hpp>
45 #include <com/sun/star/awt/FontUnderline.hpp>
46 #include <com/sun/star/awt/FontSlant.hpp>
47 #include <com/sun/star/container/XEnumerationAccess.hpp>
48 #include <com/sun/star/presentation/ParagraphTarget.hpp>
49 #include <com/sun/star/text/XSimpleText.hpp>
50 #include <com/sun/star/animations/XIterateContainer.hpp>
51 #include <com/sun/star/presentation/TextAnimationType.hpp>
53 #include <oox/ppt/pptfilterhelpers.hxx>
54 #include "pptexanimations.hxx"
55 #include "pptexsoundcollection.hxx"
56 #include "../ppt/pptanimations.hxx"
57 #include <filter/msfilter/escherex.hxx>
58 #include <osl/diagnose.h>
59 #include <tools/debug.hxx>
61 #include <algorithm>
63 using ::com::sun::star::uno::Any;
64 using ::com::sun::star::util::XCloneable;
65 using ::com::sun::star::uno::Reference;
66 using ::com::sun::star::uno::UNO_QUERY;
67 using ::com::sun::star::uno::UNO_QUERY_THROW;
68 using ::com::sun::star::uno::Sequence;
69 using ::com::sun::star::uno::Exception;
70 using ::com::sun::star::beans::NamedValue;
71 using ::com::sun::star::container::XEnumerationAccess;
72 using ::com::sun::star::container::XEnumeration;
74 using namespace ::com::sun::star::text;
75 using namespace ::com::sun::star::drawing;
76 using namespace ::com::sun::star::animations;
77 using namespace ::com::sun::star::presentation;
79 namespace ppt
82 static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
84 if ( eTranslateMode == TRANSLATE_NONE )
85 return;
87 if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
89 const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
90 while( p->mpAPIName )
92 if( rString.equalsAscii( p->mpAPIName ) )
93 break;
94 p++;
96 if( p->mpMSName )
98 if ( eTranslateMode & TRANSLATE_VALUE )
100 rString = "#";
101 rString += OUString::createFromAscii( p->mpMSName );
103 else
104 rString = OUString::createFromAscii( p->mpMSName );
107 else if ( eTranslateMode & TRANSLATE_MEASURE )
109 const sal_Char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
110 const sal_Char* pSource[] = { "x", "y", "width", "height", nullptr };
111 sal_Int32 nIndex = 0;
113 const sal_Char** ps = pSource;
114 const sal_Char** pd = pDest;
116 while( *ps )
118 const OUString aSearch( OUString::createFromAscii( *ps ) );
119 while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
121 sal_Int32 nLength = aSearch.getLength();
122 if( nIndex && ( rString[nIndex-1] == '#' ) )
124 nIndex--;
125 nLength++;
128 const OUString aNew( OUString::createFromAscii( *pd ) );
129 rString = rString.replaceAt( nIndex, nLength, aNew );
130 nIndex += aNew.getLength();
132 ps++;
133 pd++;
138 sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, const OUString& rPresetSubType )
140 sal_uInt32 nPresetSubType = 0;
141 bool bTranslated = false;
143 if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
145 if ( nPresetId != 21 )
147 switch( nPresetId )
149 case 5 :
151 if ( rPresetSubType == "downward" )
153 nPresetSubType = 5;
154 bTranslated = true;
156 else if ( rPresetSubType == "across" )
158 nPresetSubType = 10;
159 bTranslated = true;
162 break;
163 case 17 :
165 if ( rPresetSubType == "across" )
167 nPresetSubType = 10;
168 bTranslated = true;
171 break;
172 case 18 :
174 if ( rPresetSubType == "right-to-top" )
176 nPresetSubType = 3;
177 bTranslated = true;
179 else if ( rPresetSubType == "right-to-bottom" )
181 nPresetSubType = 6;
182 bTranslated = true;
184 else if ( rPresetSubType == "left-to-top" )
186 nPresetSubType = 9;
187 bTranslated = true;
189 else if ( rPresetSubType == "left-to-bottom" )
191 nPresetSubType = 12;
192 bTranslated = true;
195 break;
198 if ( !bTranslated )
200 const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
201 while( p->mpStrSubType )
203 if ( rPresetSubType.equalsAscii( p->mpStrSubType ) )
205 nPresetSubType = p->mnID;
206 bTranslated = true;
207 break;
209 p++;
213 if ( !bTranslated )
214 nPresetSubType = static_cast<sal_uInt32>(rPresetSubType.toInt32());
215 return nPresetSubType;
218 const sal_Char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
220 const sal_Char* pRet = nullptr;
221 int nFit = 0;
223 const oox::ppt::transition* p = oox::ppt::transition::getList();
224 while( p->mpName )
226 int nF = 0;
227 if ( nType == p->mnType )
228 nF += 4;
229 if ( nSubType == p->mnSubType )
230 nF += 2;
231 if ( bDirection == p->mbDirection )
232 nF += 1;
233 if ( nF > nFit )
235 pRet = p->mpName;
236 nFit = nF;
238 if ( nFit == 7 ) // maximum
239 break;
240 p++;
242 return pRet;
245 SvStream& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
247 rOut.WriteInt32( rNode.mnU1 );
248 rOut.WriteInt32( rNode.mnRestart );
249 rOut.WriteInt32( rNode.mnGroupType );
250 rOut.WriteInt32( rNode.mnFill );
251 rOut.WriteInt32( rNode.mnU3 );
252 rOut.WriteInt32( rNode.mnU4 );
253 rOut.WriteInt32( rNode.mnDuration );
254 rOut.WriteInt32( rNode.mnNodeType );
256 return rOut;
259 AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
260 mrSolverContainer ( rSolverContainer ),
261 mrExSoundCollection ( rExSoundCollection ),
262 mnCurrentGroup(0)
266 sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
268 sal_Int16 nFill = xNode->getFill();
269 //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
270 //#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.
271 if ((xNode->getType() == AnimationNodeType::ANIMATE)
272 ||(xNode->getType() == AnimationNodeType::SET)
273 ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
275 if ( nFill == AnimationFill::DEFAULT )
276 return nFill;
279 if ( nFill == AnimationFill::DEFAULT )
281 nFill = nFillDefault;
283 if( nFill == AnimationFill::AUTO )
285 nFill = AnimationFill::REMOVE;
286 bool bIsIndefiniteTiming = true;
287 Any aAny = xNode->getDuration();
288 if( aAny.hasValue() )
290 Timing eTiming;
291 if( aAny >>= eTiming )
292 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
294 if ( bIsIndefiniteTiming )
296 aAny = xNode->getEnd();
297 if( aAny.hasValue() )
299 Timing eTiming;
300 if( aAny >>= eTiming )
301 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
303 if ( bIsIndefiniteTiming )
305 if ( !xNode->getRepeatCount().hasValue() )
307 aAny = xNode->getRepeatDuration();
308 if( aAny.hasValue() )
310 Timing eTiming;
311 if( aAny >>= eTiming )
312 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
314 if ( bIsIndefiniteTiming )
315 nFill = AnimationFill::FREEZE;
320 return nFill;
323 void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
325 Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
326 if( xNodeSupplier.is() )
328 const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
329 if( xRootNode.is() )
331 processAfterEffectNodes( xRootNode );
332 exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
337 void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
341 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
342 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
343 while( xEnumeration->hasMoreElements() )
345 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
347 Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
348 if ( xEnumerationAccess2.is() )
350 Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
351 while( xEnumeration2->hasMoreElements() )
353 Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
355 Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
356 Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
357 while( xEnumeration3->hasMoreElements() )
359 Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
361 Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
362 Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
363 while( xEnumeration4->hasMoreElements() )
365 Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
367 switch( xChildNode3->getType() )
369 // found an after effect
370 case AnimationNodeType::SET:
371 case AnimationNodeType::ANIMATECOLOR:
373 Reference< XAnimationNode > xMaster;
375 Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
376 sal_Int32 nLength = aUserData.getLength();
377 const NamedValue* p = aUserData.getConstArray();
379 while( nLength-- )
381 if ( p->Name == "master-element" )
383 p->Value >>= xMaster;
384 break;
386 p++;
389 AfterEffectNodePtr pAfterEffectNode( new AfterEffectNode( xChildNode3, xMaster ) );
390 maAfterEffectNodes.push_back( pAfterEffectNode );
392 break;
400 catch( Exception& )
402 OSL_FAIL( "(@CL)AnimationExporter::processAfterEffectNodes(), exception caught!" );
406 bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
408 return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
409 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
412 bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
414 auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
415 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
416 if (aIter != maAfterEffectNodes.end())
418 xAfterEffectNode = (*aIter)->mxNode;
419 return true;
422 return false;
425 // check if this group only contain empty groups. this may happen when
426 // after effect nodes are not exported at theire original position
427 bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
429 if( xNode.is() ) switch( xNode->getType() )
431 case AnimationNodeType::PAR :
432 case AnimationNodeType::SEQ :
433 case AnimationNodeType::ITERATE :
435 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
436 if( xEnumerationAccess.is() )
438 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
439 if( xEnumeration.is() )
441 while( xEnumeration->hasMoreElements() )
443 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
444 if( xChildNode.is() && !isEmptyNode( xChildNode ) )
445 return false;
450 break;
452 case AnimationNodeType::SET :
453 case AnimationNodeType::ANIMATECOLOR :
454 return isAfterEffectNode( xNode );
455 default:
456 return false;
459 return true;
462 void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
463 const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
465 auto xNode = xNode_in;
467 if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
468 return;
470 if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
471 return;
473 if( nContainerRecType == DFF_msofbtAnimGroup )
474 mnCurrentGroup++;
476 bool bTakeBackInteractiveSequenceTimingForChild = false;
477 sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
479 Reference< XAnimationNode > xAudioNode;
480 static sal_uInt32 nAudioGroup;
483 bool bSkipChildren = false;
484 EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
485 switch( xNode->getType() )
487 case AnimationNodeType::CUSTOM :
489 exportAnimNode( rStrm, xNode, nFillDefault );
490 exportAnimPropertySet( rStrm, xNode );
491 exportAnimEvent( rStrm, xNode );
492 exportAnimValue( rStrm, xNode, false );
494 break;
496 case AnimationNodeType::PAR :
498 exportAnimNode( rStrm, xNode, nFillDefault );
499 exportAnimPropertySet( rStrm, xNode );
500 sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
501 if ( bTakeBackInteractiveSequenceTiming )
502 nFlags |= 0x40;
503 exportAnimEvent( rStrm, xNode, nFlags );
504 exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
506 break;
508 case AnimationNodeType::SEQ :
510 exportAnimNode( rStrm, xNode, nFillDefault );
511 sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
512 sal_Int32 nFlags = 12;
513 if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
515 nFlags |= 0x20;
516 bTakeBackInteractiveSequenceTimingForChild = true;
518 exportAnimAction( rStrm, xNode );
519 exportAnimEvent( rStrm, xNode, nFlags );
520 exportAnimValue( rStrm, xNode, false );
522 break;
524 case AnimationNodeType::ITERATE :
527 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
528 AnimationNode aAnim;
529 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
530 aAnim.mnNodeType = 1;
531 // attribute Restart
532 switch( xNode->getRestart() )
534 default:
535 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
536 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
537 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
538 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
540 // attribute Fill
541 switch( xNode->getFill() )
543 default:
544 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
545 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
546 case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
547 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
548 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
550 WriteAnimationNode( rStrm, aAnim );
552 exportIterate( rStrm, xNode );
553 exportAnimPropertySet( rStrm, xNode );
554 exportAnimEvent( rStrm, xNode );
555 exportAnimValue( rStrm, xNode, false );
557 break;
559 case AnimationNodeType::ANIMATE :
561 exportAnimNode( rStrm, xNode, nFillDefault );
562 exportAnimPropertySet( rStrm, xNode );
563 exportAnimEvent( rStrm, xNode );
564 exportAnimValue( rStrm, xNode, false );
565 exportAnimate( rStrm, xNode );
567 break;
569 case AnimationNodeType::SET :
571 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
572 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
574 exportAnimNode( rStrm, xNode, nFillDefault );
575 exportAnimPropertySet( rStrm, xNode );
576 exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
577 exportAnimEvent( rStrm, xNode );
578 exportAnimValue( rStrm, xNode, false );
580 else
582 bSkipChildren = true;
585 break;
587 case AnimationNodeType::ANIMATEMOTION :
589 exportAnimNode( rStrm, xNode, nFillDefault );
590 exportAnimPropertySet( rStrm, xNode );
591 exportAnimateMotion( rStrm, xNode );
592 exportAnimEvent( rStrm, xNode );
593 exportAnimValue( rStrm, xNode, false );
595 break;
597 case AnimationNodeType::ANIMATECOLOR :
599 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
600 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
602 if( bIsAfterEffectNode )
603 xNode = createAfterEffectNodeClone( xNode );
605 exportAnimNode( rStrm, xNode, nFillDefault );
606 exportAnimPropertySet( rStrm, xNode );
607 exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
608 exportAnimEvent( rStrm, xNode );
609 exportAnimValue( rStrm, xNode, false );
611 else
613 bSkipChildren = true;
616 break;
618 case AnimationNodeType::ANIMATETRANSFORM :
620 exportAnimNode( rStrm, xNode, nFillDefault );
621 exportAnimPropertySet( rStrm, xNode );
622 exportAnimateTransform( rStrm, xNode );
623 exportAnimEvent( rStrm, xNode );
624 exportAnimValue( rStrm, xNode, false );
626 break;
628 case AnimationNodeType::TRANSITIONFILTER :
630 exportAnimNode( rStrm, xNode, nFillDefault );
631 exportAnimPropertySet( rStrm, xNode );
632 exportAnimEvent( rStrm, xNode );
633 exportAnimValue( rStrm, xNode, false );
634 exportTransitionFilter( rStrm, xNode );
636 break;
638 case AnimationNodeType::AUDIO : // #i58428#
640 exportAnimNode( rStrm, xNode, nFillDefault );
641 exportAnimPropertySet( rStrm, xNode );
643 Reference< XAudio > xAudio( xNode, UNO_QUERY );
644 if( xAudio.is() )
646 Any aAny( xAudio->getSource() );
647 OUString aURL;
649 if ( ( aAny >>= aURL) && !aURL.isEmpty() )
651 sal_Int32 nU1 = 2;
652 sal_Int32 nTrigger = 3;
653 sal_Int32 nU3 = nAudioGroup;
654 sal_Int32 nBegin = 0;
656 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 );
658 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
659 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
662 nU1 = 1;
663 nTrigger = 0xb;
664 nU3 = 0;
666 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
668 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
669 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
672 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
674 sal_uInt32 const nRefMode = 3;
675 sal_uInt32 const nRefType = 2;
676 sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
677 sal_Int32 const begin = -1;
678 sal_Int32 const end = -1;
680 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
681 rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
685 exportAnimValue( rStrm, xNode, false );
687 break;
689 if( !bSkipChildren )
691 // export after effect node if one exists for this node
692 Reference< XAnimationNode > xAfterEffectNode;
693 if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
695 exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
698 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
699 if( xEnumerationAccess.is() )
701 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
702 if( xEnumeration.is() )
704 while( xEnumeration->hasMoreElements() )
706 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
707 if( xChildNode.is() )
709 if ( xChildNode->getType() == AnimationNodeType::AUDIO )
711 xAudioNode = xChildNode;
712 nAudioGroup = mnCurrentGroup;
714 else
715 exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
722 if ( xAudioNode.is() )
723 exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
725 if( xNode->getType() == AnimationNodeType::ITERATE )
726 aTarget = Any();
729 Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
733 Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
734 Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
736 Any aEmpty;
737 xCloneNode->setBegin( aEmpty );
739 return xCloneNode;
741 catch( Exception& )
743 OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
745 return xNode;
748 bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
750 // trying to get the nodetype
751 Sequence< NamedValue > aUserData = xNode->getUserData();
752 if ( aUserData.hasElements() )
754 const NamedValue* p = aUserData.getConstArray();
755 sal_Int32 nLength = aUserData.getLength();
756 while( nLength-- )
758 if ( p->Name == "node-type" )
760 if ( p->Value >>= nType )
761 return true;
766 return false;
769 void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
770 const sal_Int16 nFillDefault )
772 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
773 AnimationNode aAnim;
775 // attribute Restart
776 switch( xNode->getRestart() )
778 default:
779 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
780 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
781 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
782 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
785 switch( nFillDefault )
787 default:
788 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
789 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
790 case AnimationFill::FREEZE :
791 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
792 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
794 // attribute Duration
795 double fDuration = 0.0;
796 css::animations::Timing eTiming;
797 if ( xNode->getDuration() >>= eTiming )
799 if ( eTiming == Timing_INDEFINITE )
800 aAnim.mnDuration = -1;
802 else if ( xNode->getDuration() >>= fDuration )
804 aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
806 else
807 aAnim.mnDuration = -1;
809 // NodeType, NodeGroup
810 aAnim.mnNodeType = 1;
811 aAnim.mnGroupType = mso_Anim_GroupType_SEQ;
812 switch( xNode->getType() )
814 case AnimationNodeType::PAR :
815 aAnim.mnGroupType = mso_Anim_GroupType_PAR;
816 [[fallthrough]];
817 case AnimationNodeType::SEQ :
819 sal_Int16 nType = 0;
820 if( GetNodeType( xNode, nType ) )
821 switch( nType )
823 case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
824 case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
827 break;
829 case AnimationNodeType::ANIMATE :
830 case AnimationNodeType::SET :
832 case AnimationNodeType::CUSTOM :
833 case AnimationNodeType::ITERATE :
834 case AnimationNodeType::ANIMATEMOTION :
835 case AnimationNodeType::ANIMATECOLOR :
836 case AnimationNodeType::ANIMATETRANSFORM :
838 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
839 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
841 break;
843 case AnimationNodeType::AUDIO :
845 aAnim.mnGroupType = mso_Anim_GroupType_MEDIA;
846 aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION;
848 break;
850 case AnimationNodeType::TRANSITIONFILTER :
852 aAnim.mnGroupType = mso_Anim_GroupType_NODE;
853 aAnim.mnNodeType = mso_Anim_Behaviour_FILTER;
855 break;
858 WriteAnimationNode( rStrm, aAnim );
861 void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
863 // storing user data into pAny, to allow direct access later
864 memset( pAny, 0, nLen );
865 if ( !rUserData.hasElements() )
866 return;
868 const NamedValue* p = rUserData.getConstArray();
869 sal_Int32 nLength = rUserData.getLength();
870 while( nLength-- )
872 if ( p->Name == "node-type" )
874 pAny[ DFF_ANIM_NODE_TYPE ] = &(p->Value);
876 else if ( p->Name == "preset-class" )
878 pAny[ DFF_ANIM_PRESET_CLASS ] = &(p->Value);
880 else if ( p->Name == "preset-id" )
882 pAny[ DFF_ANIM_PRESET_ID ] = &(p->Value);
884 else if ( p->Name == "preset-sub-type" )
886 pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(p->Value);
888 else if ( p->Name == "master-element" )
890 pAny[ DFF_ANIM_AFTEREFFECT ] = &(p->Value);
892 p++;
896 sal_uInt32 AnimationExporter::GetPresetID( const OUString& rPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
898 sal_uInt32 nPresetId = 0;
899 bPresetId = false;
901 if ( rPreset.match("ppt_", 0) )
903 sal_Int32 nLast = rPreset.lastIndexOf( '_' );
904 if ( ( nLast != -1 ) && ( ( nLast + 1 ) < rPreset.getLength() ) )
906 OUString aNumber( rPreset.copy( nLast + 1 ) );
907 nPresetId = aNumber.toInt32();
908 bPresetId = true;
911 else
913 const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
914 while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !rPreset.equalsAscii( p->mpStrPresetId )) )
915 p++;
917 if( p->mpStrPresetId )
919 nPresetId = p->mnPresetId;
920 bPresetId = true;
924 return nPresetId;
927 sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
929 sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
931 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
933 Reference< XAnimationNode > xMaster;
935 Any aMasterRel, aOverride, aRunTimeContext;
937 // storing user data into pAny, to allow direct access later
938 const Sequence< NamedValue > aUserData = xNode->getUserData();
939 const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
940 GetUserData( aUserData, pAny, sizeof( pAny ) );
942 if( pAny[ DFF_ANIM_AFTEREFFECT ] )
943 ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
945 // calculate master-rel
946 if( xMaster.is() )
948 sal_Int32 nMasterRel = 2;
949 if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
950 nMasterRel = 0;
952 aMasterRel <<= nMasterRel;
954 pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
956 aOverride <<= sal_Int32(1);
957 pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
959 aRunTimeContext <<= sal_Int32(1);
960 pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
963 // the order is important
964 if ( pAny[ DFF_ANIM_NODE_TYPE ] )
966 if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
968 sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
969 switch( nNodeType )
971 case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
972 case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
973 case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
974 case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
975 case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
976 case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
978 exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
981 sal_uInt32 nPresetId = 0;
982 sal_uInt32 nPresetSubType = 0;
983 sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
984 sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
985 bool bPresetClass, bPresetId, bPresetSubType;
986 bPresetId = bPresetClass = bPresetSubType = false;
988 if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
990 if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
992 sal_uInt8 nPPTPresetClass;
993 switch( nAPIPresetClass )
995 case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
996 case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
997 case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
998 case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
999 case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
1000 case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
1001 default :
1002 nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
1004 nPresetClass = nPPTPresetClass;
1005 bPresetClass = true;
1008 if ( pAny[ DFF_ANIM_PRESET_ID ] )
1010 OUString sPreset;
1011 if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
1012 nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
1015 if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
1017 OUString sPresetSubType;
1018 if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
1020 nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
1021 bPresetSubType = true;
1024 if ( bPresetId )
1025 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
1026 if ( bPresetSubType )
1027 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
1028 if ( bPresetClass )
1029 exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
1031 if ( pAny[ DFF_ANIM_ID ] )
1033 // TODO DFF_ANIM_ID
1036 if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
1038 bool bAfterEffect = false;
1039 if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
1040 exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
1043 if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
1045 sal_Int32 nRunTimeContext = 0;
1046 if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
1047 exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
1049 if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
1051 // TODO DFF_ANIM_ID
1054 if( !xMaster.is() )
1056 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
1057 if( xColor.is() )
1060 bool bDirection = !xColor->getDirection();
1061 exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
1065 if ( pAny[ DFF_ANIM_OVERRIDE ] )
1067 sal_Int32 nOverride = 0;
1068 if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
1069 exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
1072 if ( pAny[ DFF_ANIM_MASTERREL ] )
1074 sal_Int32 nMasterRel = 0;
1075 if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
1076 exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
1079 /* todo
1080 Reference< XAudio > xAudio( xNode, UNO_QUERY );
1081 if( xAudio.is() )
1083 sal_Int16 nEndAfterSlide = 0;
1084 nEndAfterSlide = xAudio->getEndAfterSlide();
1085 exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
1088 Reference< XAnimate > xAnim( xNode, UNO_QUERY );
1089 if( xAnim.is() )
1091 // TODO: DFF_ANIM_TIMEFILTER
1093 if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
1095 // TODO DFF_ANIM_EVENT_FILTER
1097 if ( pAny[ DFF_ANIM_VOLUME ] )
1099 // TODO DFF_ANIM_VOLUME
1101 return nNodeType;
1104 bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
1106 bool bRet = false;
1107 if ( rAny.hasValue() )
1109 switch( rAny.getValueType().getTypeClass() )
1111 case css::uno::TypeClass_UNSIGNED_SHORT :
1112 case css::uno::TypeClass_SHORT :
1113 case css::uno::TypeClass_UNSIGNED_LONG :
1114 case css::uno::TypeClass_LONG :
1116 sal_Int32 nVal = 0;
1117 if ( rAny >>= nVal )
1119 exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
1120 bRet = true;
1123 break;
1125 case css::uno::TypeClass_DOUBLE :
1127 double fVal = 0.0;
1128 if ( rAny >>= fVal )
1130 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1131 bRet = true;
1134 break;
1135 case css::uno::TypeClass_FLOAT :
1137 float fVal = 0.0;
1138 if ( rAny >>= fVal )
1140 if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
1142 OUString aNumber( OUString::number( fVal ) );
1143 exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
1145 else
1147 exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
1148 bRet = true;
1152 break;
1153 case css::uno::TypeClass_STRING :
1155 OUString aStr;
1156 if ( rAny >>= aStr )
1158 exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
1159 bRet = true;
1162 break;
1163 default:
1164 break;
1167 return bRet;
1169 void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
1171 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1172 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
1173 OUString aStr( rVal );
1174 if ( eTranslateMode != TRANSLATE_NONE )
1175 ImplTranslateAttribute( aStr, eTranslateMode );
1176 writeZString( rStrm, aStr );
1179 void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
1181 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1182 float fFloat = static_cast<float>(rVal);
1183 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
1184 .WriteFloat( fFloat );
1187 void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
1189 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1190 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
1191 .WriteUInt32( nVal );
1194 void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
1196 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
1197 rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
1198 .WriteUChar( nVal );
1201 void AnimationExporter::writeZString( SvStream& rStrm, const OUString& rVal )
1203 sal_Int32 i;
1204 for ( i = 0; i < rVal.getLength(); i++ )
1205 rStrm.WriteUInt16( rVal[ i ] );
1206 rStrm.WriteUInt16( 0 );
1209 void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1211 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
1213 sal_Int32 const nConcurrent = 1;
1214 sal_Int32 const nNextAction = 1;
1215 sal_Int32 nEndSync = 0;
1216 sal_Int32 const nU4 = 0;
1217 sal_Int32 const nU5 = 3;
1219 sal_Int16 nAnimationEndSync = 0;
1220 if ( xNode->getEndSync() >>= nAnimationEndSync )
1222 if ( nAnimationEndSync == AnimationEndSync::ALL )
1223 nEndSync = 1;
1225 rStrm.WriteInt32( nConcurrent )
1226 .WriteInt32( nNextAction )
1227 .WriteInt32( nEndSync )
1228 .WriteInt32( nU4 )
1229 .WriteInt32( nU5 );
1233 // nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
1234 // nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
1235 // nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
1236 void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
1238 sal_uInt16 i;
1239 for ( i = 0; i < 4; i++ )
1241 sal_Int32 nU1 = 0;
1242 sal_Int32 nTrigger = 0;
1243 sal_Int32 nU3 = 0;
1244 sal_Int32 nBegin = 0;
1246 bool bCreateEvent = false;
1247 Any aSource;
1249 switch( i )
1251 case 0 :
1252 case 1 :
1254 Any aAny;
1255 Event aEvent;
1256 css::animations::Timing eTiming;
1257 if ( i == 0 )
1259 if ( nFlags & 0x20 )
1261 // taking the first child
1262 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
1263 Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
1264 if ( xE->hasMoreElements() )
1266 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
1267 aAny = xClickNode->getBegin();
1270 else if ( nFlags & 0x40 )
1272 // begin has to be replaced with void, so don't do anything
1274 else
1276 aAny = xNode->getBegin();
1277 if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
1279 if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
1281 eTiming = Timing_INDEFINITE;
1282 aAny <<= eTiming;
1287 else
1288 aAny = xNode->getEnd();
1290 double fTiming = 0.0;
1291 if ( aAny >>= aEvent )
1293 bCreateEvent = true;
1294 switch( aEvent.Trigger )
1296 case EventTrigger::NONE : nTrigger = 0; break;
1297 case EventTrigger::ON_BEGIN : nTrigger = 1; break;
1298 case EventTrigger::ON_END : nTrigger = 2; break;
1299 case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
1300 case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
1301 case EventTrigger::ON_CLICK : nTrigger = 5; break;
1302 case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
1303 case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
1304 case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
1305 case EventTrigger::ON_NEXT : nTrigger = 9; break;
1306 case EventTrigger::ON_PREV : nTrigger = 10; break;
1307 case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
1309 if ( aEvent.Offset.hasValue() )
1311 if ( aEvent.Offset >>= eTiming )
1313 if ( eTiming == Timing_INDEFINITE )
1314 nBegin = -1;
1316 else if ( aEvent.Offset >>= fTiming )
1317 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1319 aSource = aEvent.Source;
1321 else if ( aAny >>= eTiming )
1323 bCreateEvent = true;
1324 if ( eTiming == Timing_INDEFINITE )
1325 nBegin = -1;
1327 else if ( aAny >>= fTiming )
1329 bCreateEvent = true;
1330 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1333 break;
1335 case 2 :
1337 if ( nFlags & ( 1 << i ) )
1339 bCreateEvent = true;
1340 nU1 = 1;
1341 nTrigger = 9;
1344 break;
1345 case 3 :
1347 if ( nFlags & ( 1 << i ) )
1349 bCreateEvent = true;
1350 nU1 = 1;
1351 nTrigger = 10;
1354 break;
1356 if ( bCreateEvent )
1358 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
1360 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
1361 rStrm.WriteInt32( nU1 )
1362 .WriteInt32( nTrigger )
1363 .WriteInt32( nU3 )
1364 .WriteInt32( nBegin );
1366 exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
1371 Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, const OUString& rAttributeName )
1373 OUString aDest;
1374 if ( rAttributeName == "X"
1375 || rAttributeName == "Y"
1376 || rAttributeName == "Width"
1377 || rAttributeName == "Height"
1380 OUString aStr;
1381 if ( rSourceValue >>= aStr )
1383 ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
1384 aDest += aStr;
1387 else if ( rAttributeName == "Rotate" // "r" or "style.rotation" ?
1388 || rAttributeName == "Opacity"
1389 || rAttributeName == "CharHeight"
1390 || rAttributeName == "SkewX"
1393 double fNumber = 0.0;
1394 if ( rSourceValue >>= fNumber )
1395 aDest += OUString::number( fNumber );
1397 else if ( rAttributeName == "Color"
1398 || rAttributeName == "FillColor" // "Fillcolor" or "FillColor" ?
1399 || rAttributeName == "LineColor"
1400 || rAttributeName == "CharColor"
1403 sal_Int32 nColor = 0;
1404 Sequence< double > aHSL( 3 );
1405 OUString aP( "," );
1406 if ( rSourceValue >>= aHSL )
1408 aDest += "hsl("
1409 + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
1410 + aP
1411 + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
1412 + aP
1413 + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
1414 + ")";
1416 else if ( rSourceValue >>= nColor )
1418 aDest += "rgb("
1419 + OUString::number( static_cast<sal_Int8>(nColor) )
1420 + aP
1421 + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
1422 + aP
1423 + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
1424 + ")";
1427 else if ( rAttributeName == "FillStyle" )
1429 css::drawing::FillStyle eFillStyle;
1430 if ( rSourceValue >>= eFillStyle )
1432 if ( eFillStyle == css::drawing::FillStyle_NONE )
1433 aDest += "none"; // ?
1434 else
1435 aDest += "solid";
1438 else if (rAttributeName == "FillOn")
1440 bool bFillOn;
1441 if ( rSourceValue >>= bFillOn )
1443 if ( bFillOn )
1444 aDest += "true";
1445 else
1446 aDest += "false";
1449 else if ( rAttributeName == "LineStyle" )
1451 css::drawing::LineStyle eLineStyle;
1452 if ( rSourceValue >>= eLineStyle )
1454 if ( eLineStyle == css::drawing::LineStyle_NONE )
1455 aDest += "false";
1456 else
1457 aDest += "true";
1460 else if ( rAttributeName == "CharWeight" )
1462 float fFontWeight = 0.0;
1463 if ( rSourceValue >>= fFontWeight )
1465 if ( fFontWeight == css::awt::FontWeight::BOLD )
1466 aDest += "bold";
1467 else
1468 aDest += "normal";
1471 else if ( rAttributeName == "CharUnderline" )
1473 sal_Int16 nFontUnderline = 0;
1474 if ( rSourceValue >>= nFontUnderline )
1476 if ( nFontUnderline == css::awt::FontUnderline::NONE )
1477 aDest += "false";
1478 else
1479 aDest += "true";
1482 else if ( rAttributeName == "CharPosture" )
1484 css::awt::FontSlant eFontSlant;
1485 if ( rSourceValue >>= eFontSlant )
1487 if ( eFontSlant == css::awt::FontSlant_ITALIC )
1488 aDest += "italic";
1489 else
1490 aDest += "normal"; // ?
1493 else if ( rAttributeName == "Visibility" )
1495 bool bVisible = true;
1496 if ( rSourceValue >>= bVisible )
1498 if ( bVisible )
1499 aDest += "visible";
1500 else
1501 aDest += "hidden";
1504 Any aRet;
1505 if ( !aDest.isEmpty() )
1506 aRet <<= aDest;
1507 else
1508 aRet = rSourceValue;
1509 return aRet;
1512 void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
1514 Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
1515 if( !xSet.is() )
1516 return;
1518 EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
1520 EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
1521 sal_uInt32 const nId1 = 1; // ??
1522 sal_uInt32 const nId2 = 1; // ??
1523 rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
1525 Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
1526 if ( aConvertedValue.hasValue() )
1527 exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
1528 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
1531 sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( const OUString& rAttributeName )
1533 sal_uInt32 nValueType = 0;
1535 struct Entry
1537 const sal_Char* pName;
1538 sal_uInt8 nType;
1540 static const Entry lcl_attributeMap[] =
1542 { "charcolor", 2 },
1543 { "charfontname", 0 },
1544 { "charheight", 1 },
1545 { "charposture", 0 },
1546 // TODO(Q1): This should prolly be changed in PPT import
1547 // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
1548 { "charrotation", 1 },
1549 { "charunderline", 0 },
1550 { "charweight", 0 },
1551 { "color", 2 },
1552 { "dimcolor", 2 },
1553 { "fillcolor", 2 },
1554 { "fillstyle", 0 },
1555 { "height", 1 },
1556 { "linecolor", 2 },
1557 { "linestyle", 0 },
1558 { "opacity", 0 },
1559 { "rotate", 1 },
1560 { "skewx", 1 },
1561 { "skewy", 1 },
1562 { "visibility", 1 },
1563 { "width", 1 },
1564 { "x", 1 },
1565 { "y", 1 },
1566 { nullptr, 0 }
1568 const Entry* pPtr = &lcl_attributeMap[ 0 ];
1569 while( pPtr->pName )
1571 if ( rAttributeName.equalsIgnoreAsciiCaseAscii( pPtr->pName ) )
1573 nValueType = pPtr->nType;
1574 break;
1576 pPtr++;
1578 DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
1579 return nValueType;
1582 void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1584 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1585 if ( !xAnimate.is() )
1586 return;
1588 Any aBy ( xAnimate->getBy() );
1589 Any aFrom( xAnimate->getFrom() );
1590 Any aTo ( xAnimate->getTo() );
1592 EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
1594 EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
1595 sal_uInt32 nBits = 0x38;
1596 sal_Int16 nTmp = xAnimate->getCalcMode();
1597 sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
1598 sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
1600 if ( aBy.hasValue() )
1601 nBits |= 1;
1602 if ( aFrom.hasValue() )
1603 nBits |= 2;
1604 if ( aTo.hasValue() )
1605 nBits |= 4;
1607 rStrm.WriteUInt32( nCalcMode )
1608 .WriteUInt32( nBits )
1609 .WriteUInt32( nValueType );
1611 if ( aBy.hasValue() )
1612 exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1613 if ( aFrom.hasValue() )
1614 exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1615 if ( aTo.hasValue() )
1616 exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE );
1618 exportAnimateKeyPoints( rStrm, xAnimate );
1619 exportAnimateTarget( rStrm, xNode );
1622 void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
1624 EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
1625 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1626 if ( !xAnimate.is() )
1627 return;
1630 EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
1631 // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
1632 // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
1633 // nAccumulate 0 = none, 1 = always
1634 // nTransformType 0: "property" else "image"
1635 sal_uInt32 nBits = 0;
1636 sal_uInt32 nAdditive = 0;
1637 sal_uInt32 nAccumulate = 0;
1638 sal_uInt32 const nTransformType = 0;
1639 if ( xAnimate.is() )
1641 if ( !xAnimate->getAttributeName().isEmpty() )
1642 nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
1643 sal_Int16 nAdditiveMode = xAnimate->getAdditive();
1644 if ( nAdditiveMode != AnimationAdditiveMode::BASE )
1646 nBits |= 1;
1647 switch( nAdditiveMode )
1649 case AnimationAdditiveMode::SUM : nAdditive = 1; break;
1650 case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
1651 case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
1652 case AnimationAdditiveMode::NONE : nAdditive = 4; break;
1655 if ( xAnimate->getAccumulate() )
1657 nBits |= 2;
1658 nAccumulate = 1;
1661 rStrm.WriteUInt32( nBits )
1662 .WriteUInt32( nAdditive )
1663 .WriteUInt32( nAccumulate )
1664 .WriteUInt32( nTransformType );
1666 if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
1668 EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
1669 OUString aAttributeName( xAnimate->getAttributeName() );
1670 if ( nForceAttributeNames )
1672 if( nForceAttributeNames == 1 )
1674 aAttributeName = "r";
1677 sal_Int32 nIndex = 0;
1680 OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
1681 exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE );
1683 while ( nIndex >= 0 );
1686 if( nAfterEffectType != AFTEREFFECT_NONE )
1688 EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
1689 exportAnimPropertyuInt32( rStrm, 6, 1 );
1690 if( nAfterEffectType == AFTEREFFECT_COLOR )
1692 exportAnimPropertyuInt32( rStrm, 4, 0 );
1693 exportAnimPropertyuInt32( rStrm, 5, 0 );
1696 exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
1699 Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
1701 Reference< XShape > xShape;
1702 rAny >>= xShape;
1704 rParagraphTarget = false;
1706 if( !xShape.is() )
1708 ParagraphTarget aParaTarget;
1709 if( rAny >>= aParaTarget )
1710 xShape = aParaTarget.Shape;
1711 if ( xShape.is() )
1713 // now calculating the character range for the paragraph
1714 sal_Int16 nParagraph = aParaTarget.Paragraph;
1715 Reference< XSimpleText > xText( xShape, UNO_QUERY );
1716 if ( xText.is() )
1718 rParagraphTarget = true;
1719 Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
1720 if ( xTextParagraphEnumerationAccess.is() )
1722 Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
1723 if ( xTextParagraphEnumeration.is() )
1725 sal_Int16 nCurrentParagraph;
1726 rBegin = rEnd = nCurrentParagraph = 0;
1727 while ( xTextParagraphEnumeration->hasMoreElements() )
1729 Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
1730 if ( xTextRange.is() )
1732 OUString aParaText( xTextRange->getString() );
1733 sal_Int32 nLength = aParaText.getLength() + 1;
1734 rEnd += nLength;
1735 if ( nCurrentParagraph == nParagraph )
1736 break;
1737 nCurrentParagraph++;
1738 rBegin += nLength;
1747 return xShape;
1750 void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
1752 sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
1753 sal_Int32 begin = -1;
1754 sal_Int32 end = -1;
1755 bool bParagraphTarget;
1757 Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
1759 if( bParagraphTarget )
1760 nRefMode = 2;
1762 if ( !(xShape.is() || bCreate2b01Atom) )
1763 return;
1765 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
1766 if ( xShape.is() )
1768 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
1770 sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
1771 sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
1773 rStrm.WriteUInt32( nRefMode )
1774 .WriteUInt32( nRefType )
1775 .WriteUInt32( nRefId )
1776 .WriteInt32( begin )
1777 .WriteInt32( end );
1779 if ( bCreate2b01Atom )
1781 EscherExAtom a2b01Atom( rStrm, 0x2b01 );
1782 rStrm.WriteUInt32( 1 ); // ?
1786 void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
1788 Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
1789 Sequence< Any > aValues( xAnimate->getValues() );
1790 OUString aFormula( xAnimate->getFormula() );
1791 if ( !aKeyTimes.hasElements() )
1792 return;
1794 EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
1795 sal_Int32 i;
1796 for ( i = 0; i < aKeyTimes.getLength(); i++ )
1799 EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
1800 sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
1801 rStrm.WriteInt32( nKeyTime );
1803 Any aAny[ 2 ];
1804 if ( aValues[ i ].hasValue() )
1806 ValuePair aPair;
1807 if ( aValues[ i ] >>= aPair )
1809 aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
1810 aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
1812 else
1814 aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
1816 if ( !i && !aFormula.isEmpty() )
1818 ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE );
1819 aAny[ 1 ] <<= aFormula;
1821 exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
1822 exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
1827 void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
1829 Any aAny;
1830 // repeat count (0)
1831 double fRepeat = 0.0;
1832 float fRepeatCount = 0.0;
1833 css::animations::Timing eTiming;
1834 aAny = xNode->getRepeatCount();
1835 if ( aAny >>= eTiming )
1837 if ( eTiming == Timing_INDEFINITE )
1838 fRepeatCount = (float(3.40282346638528860e+38));
1840 else if ( aAny >>= fRepeat )
1841 fRepeatCount = static_cast<float>(fRepeat);
1842 if ( fRepeatCount != 0.0 )
1844 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1845 sal_uInt32 const nType = 0;
1846 rStrm.WriteUInt32( nType )
1847 .WriteFloat( fRepeatCount );
1849 // accelerate (3)
1850 float fAccelerate = static_cast<float>(xNode->getAcceleration());
1851 if ( bExportAlways || ( fAccelerate != 0.0 ) )
1853 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1854 sal_uInt32 const nType = 3;
1855 rStrm.WriteUInt32( nType )
1856 .WriteFloat( fAccelerate );
1859 // decelerate (4)
1860 float fDecelerate = static_cast<float>(xNode->getDecelerate());
1861 if ( bExportAlways || ( fDecelerate != 0.0 ) )
1863 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1864 sal_uInt32 const nType = 4;
1865 rStrm.WriteUInt32( nType )
1866 .WriteFloat( fDecelerate );
1869 // autoreverse (5)
1870 bool bAutoReverse = xNode->getAutoReverse();
1871 if ( bExportAlways || bAutoReverse )
1873 EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
1874 sal_uInt32 const nType = 5;
1875 sal_uInt32 nVal = bAutoReverse ? 1 : 0;
1876 rStrm.WriteUInt32( nType )
1877 .WriteUInt32( nVal );
1881 void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1883 Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
1884 if ( !xFilter.is() )
1885 return;
1887 EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
1889 EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
1890 sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
1891 // bit 1 -> use nTransition
1893 sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
1894 rStrm.WriteUInt32( nBits )
1895 .WriteUInt32( nTransition );
1897 const sal_Char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
1898 if ( pFilter )
1900 const OUString aStr( OUString::createFromAscii( pFilter ) );
1901 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1903 exportAnimateTarget( rStrm, xNode );
1906 void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1908 Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
1909 if ( !xMotion.is() )
1910 return;
1912 EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
1914 { //SJ: Ignored from import filter
1915 EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
1916 sal_uInt32 const nBits = 0x98;
1917 sal_uInt32 const nOrigin = 0x2;
1918 float const fByX = 100.0; // nBits&1
1919 float const fByY = 100.0; // nBits&1
1920 float const fFromX = 0.0; // nBits&2
1921 float const fFromY = 0.0; // nBits&2
1922 float const fToX = 100.0; // nBits&4
1923 float const fToY = 100.0; // nBits&4
1924 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
1927 OUString aStr;
1928 if ( xMotion->getPath() >>= aStr )
1930 if ( !aStr.isEmpty() )
1931 exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE );
1933 exportAnimateTarget( rStrm, xNode );
1937 void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1939 Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
1940 if ( !xTransform.is() )
1941 return;
1943 if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
1945 EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
1947 EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
1948 sal_uInt32 nBits = 0;
1949 sal_uInt32 const nZoomContents = 1;
1950 float fByX = 100.0;
1951 float fByY = 100.0;
1952 float fFromX = 0.0;
1953 float fFromY = 0.0;
1954 float fToX = 100.0;
1955 float fToY = 100.0;
1957 double fX = 0.0, fY = 0.0;
1958 ValuePair aPair;
1959 if ( xTransform->getBy() >>= aPair )
1961 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1963 nBits |= 1;
1964 fByX = static_cast<float>( fX * 100 );
1965 fByY = static_cast<float>( fY * 100 );
1968 if ( xTransform->getFrom() >>= aPair )
1970 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1972 nBits |= 2;
1973 fFromX = static_cast<float>( fX * 100 );
1974 fFromY = static_cast<float>( fY * 100 );
1977 if( xTransform->getTo() >>= aPair )
1979 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1981 nBits |= 4;
1982 fToX = static_cast<float>( fX * 100 );
1983 fToY = static_cast<float>( fY * 100 );
1987 // TODO: ZoomContents:
1988 //if( nBits & 8 )
1989 //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
1991 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
1993 exportAnimateTarget( rStrm, xNode );
1995 else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
1997 EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation );
1999 EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
2000 sal_uInt32 nBits = 0;
2001 sal_uInt32 const nU1 = 0;
2002 float fBy = 360.0;
2003 float fFrom = 0.0;
2004 float fTo = 360.0;
2006 double fVal = 0.0;
2007 if ( xTransform->getBy() >>= fVal )
2009 nBits |= 1;
2010 fBy = static_cast<float>(fVal);
2012 if ( xTransform->getFrom() >>= fVal )
2014 nBits |= 2;
2015 fFrom = static_cast<float>(fVal);
2017 if ( xTransform->getTo() >>= fVal )
2019 nBits |= 4;
2020 fTo = static_cast<float>(fVal);
2022 rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
2024 exportAnimateTarget( rStrm, xNode, 1 );
2028 bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
2030 bool bIsColor = true;
2032 rMode = 0;
2033 if ( nColorSpace == AnimationColorSpace::HSL )
2034 rMode = 1;
2036 sal_Int32 nColor = 0;
2037 Sequence< double > aHSL( 3 );
2038 if ( rAny >>= nColor ) // RGB color
2040 rA = static_cast<sal_uInt8>( nColor >> 16 );
2041 rB = static_cast<sal_uInt8>( nColor >> 8 );
2042 rC = static_cast<sal_uInt8>(nColor);
2044 else if ( rAny >>= aHSL ) // HSL
2046 rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
2047 rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
2048 rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
2050 else
2051 bIsColor = false;
2052 return bIsColor;
2055 void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
2057 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
2058 if ( !xColor.is() )
2059 return;
2061 EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor );
2063 EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
2064 sal_uInt32 nBits = 8;
2066 sal_Int32 nByMode, nByA, nByB, nByC;
2067 nByMode = nByA = nByB = nByC = 0;
2069 sal_Int32 nFromMode, nFromA, nFromB, nFromC;
2070 nFromMode = nFromA = nFromB = nFromC = 0;
2072 sal_Int32 nToMode, nToA, nToB, nToC;
2073 nToMode = nToA = nToB = nToC = 0;
2075 sal_Int16 nColorSpace = xColor->getColorInterpolation();
2077 Any aAny( xColor->getBy() );
2078 if ( aAny.hasValue() )
2080 if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
2081 nBits |= 0x11;
2083 aAny = xColor->getFrom();
2084 if ( aAny.hasValue() )
2086 if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
2087 nBits |= 0x12;
2089 aAny = xColor->getTo();
2090 if ( aAny.hasValue() )
2092 if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
2093 nBits |= 0x14;
2095 rStrm .WriteUInt32( nBits )
2096 .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
2097 .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
2098 .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
2100 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
2103 void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
2105 Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
2106 if ( !xIterate.is() )
2107 return;
2109 EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
2111 float fInterval = 10.0;
2112 sal_Int32 nTextUnitEffect = 0;
2113 sal_Int32 const nU1 = 1;
2114 sal_Int32 const nU2 = 1;
2115 sal_Int32 const nU3 = 0xe;
2117 sal_Int16 nIterateType = xIterate->getIterateType();
2118 switch( nIterateType )
2120 case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
2121 case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
2124 fInterval = static_cast<float>(xIterate->getIterateInterval());
2126 // convert interval from absolute to percentage
2127 double fDuration = 0.0;
2129 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
2130 if( xEnumerationAccess.is() )
2132 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY );
2133 if( xEnumeration.is() )
2135 while( xEnumeration->hasMoreElements() )
2137 Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
2138 if( xChildNode.is() )
2140 double fChildBegin = 0.0;
2141 double fChildDuration = 0.0;
2142 xChildNode->getBegin() >>= fChildBegin;
2143 xChildNode->getDuration() >>= fChildDuration;
2145 fChildDuration += fChildBegin;
2146 if( fChildDuration > fDuration )
2147 fDuration = fChildDuration;
2153 if( fDuration )
2154 fInterval = static_cast<float>(100.0 * fInterval / fDuration);
2156 rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
2157 aTarget = xIterate->getTarget();
2160 } // namespace ppt;
2162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */