LibreOffice Module sd (master) 1
pptexanimations.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
53
55#include "pptexanimations.hxx"
57#include "../ppt/pptanimations.hxx"
59#include <osl/diagnose.h>
60#include <tools/debug.hxx>
62#include <o3tl/string_view.hxx>
63
64#include <algorithm>
65
66using ::com::sun::star::uno::Any;
67using ::com::sun::star::util::XCloneable;
68using ::com::sun::star::uno::Reference;
69using ::com::sun::star::uno::UNO_QUERY;
70using ::com::sun::star::uno::UNO_QUERY_THROW;
71using ::com::sun::star::uno::Sequence;
72using ::com::sun::star::uno::Exception;
73using ::com::sun::star::beans::NamedValue;
74using ::com::sun::star::container::XEnumerationAccess;
75using ::com::sun::star::container::XEnumeration;
76
77using namespace ::com::sun::star::text;
78using namespace ::com::sun::star::drawing;
79using namespace ::com::sun::star::animations;
80using namespace ::com::sun::star::presentation;
81
82namespace ppt
83{
84
85static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
86{
87 if ( eTranslateMode == TRANSLATE_NONE )
88 return;
89
90 if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
91 {
93 while( p->mpAPIName )
94 {
95 if( rString.equalsAscii( p->mpAPIName ) )
96 break;
97 p++;
98 }
99 if( p->mpMSName )
100 {
101 if ( eTranslateMode & TRANSLATE_VALUE )
102 {
103 rString = "#";
104 rString += OUString::createFromAscii( p->mpMSName );
105 }
106 else
107 rString = OUString::createFromAscii( p->mpMSName );
108 }
109 }
110 else if ( eTranslateMode & TRANSLATE_MEASURE )
111 {
112 const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
113 const char* pSource[] = { "x", "y", "width", "height", nullptr };
114 sal_Int32 nIndex = 0;
115
116 const char** ps = pSource;
117 const char** pd = pDest;
118
119 while( *ps )
120 {
121 const OUString aSearch( OUString::createFromAscii( *ps ) );
122 while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
123 {
124 sal_Int32 nLength = aSearch.getLength();
125 if( nIndex && ( rString[nIndex-1] == '#' ) )
126 {
127 nIndex--;
128 nLength++;
129 }
130
131 const OUString aNew( OUString::createFromAscii( *pd ) );
132 rString = rString.replaceAt( nIndex, nLength, aNew );
133 nIndex += aNew.getLength();
134 }
135 ps++;
136 pd++;
137 }
138 }
139}
140
141sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType )
142{
143 sal_uInt32 nPresetSubType = 0;
144 bool bTranslated = false;
145
146 if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
147 {
148 if ( nPresetId != 21 )
149 {
150 switch( nPresetId )
151 {
152 case 5 :
153 {
154 if ( rPresetSubType == u"downward" )
155 {
156 nPresetSubType = 5;
157 bTranslated = true;
158 }
159 else if ( rPresetSubType == u"across" )
160 {
161 nPresetSubType = 10;
162 bTranslated = true;
163 }
164 }
165 break;
166 case 17 :
167 {
168 if ( rPresetSubType == u"across" )
169 {
170 nPresetSubType = 10;
171 bTranslated = true;
172 }
173 }
174 break;
175 case 18 :
176 {
177 if ( rPresetSubType == u"right-to-top" )
178 {
179 nPresetSubType = 3;
180 bTranslated = true;
181 }
182 else if ( rPresetSubType == u"right-to-bottom" )
183 {
184 nPresetSubType = 6;
185 bTranslated = true;
186 }
187 else if ( rPresetSubType == u"left-to-top" )
188 {
189 nPresetSubType = 9;
190 bTranslated = true;
191 }
192 else if ( rPresetSubType == u"left-to-bottom" )
193 {
194 nPresetSubType = 12;
195 bTranslated = true;
196 }
197 }
198 break;
199 }
200 }
201 if ( !bTranslated )
202 {
204 while( p->mpStrSubType )
205 {
206 if ( o3tl::equalsAscii( rPresetSubType, p->mpStrSubType ) )
207 {
208 nPresetSubType = p->mnID;
209 bTranslated = true;
210 break;
211 }
212 p++;
213 }
214 }
215 }
216 if ( !bTranslated )
217 nPresetSubType = o3tl::toUInt32(rPresetSubType);
218 return nPresetSubType;
219}
220
221const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
222{
223 const char* pRet = nullptr;
224 int nFit = 0;
225
227 while( p->mpName )
228 {
229 int nF = 0;
230 if ( nType == p->mnType )
231 nF += 4;
232 if ( nSubType == p->mnSubType )
233 nF += 2;
234 if ( bDirection == p->mbDirection )
235 nF += 1;
236 if ( nF > nFit )
237 {
238 pRet = p->mpName;
239 nFit = nF;
240 }
241 if ( nFit == 7 ) // maximum
242 break;
243 p++;
244 }
245 return pRet;
246}
247
249{
250 rOut.WriteInt32( rNode.mnU1 );
251 rOut.WriteInt32( rNode.mnRestart );
252 rOut.WriteInt32( rNode.mnGroupType );
253 rOut.WriteInt32( rNode.mnFill );
254 rOut.WriteInt32( rNode.mnU3 );
255 rOut.WriteInt32( rNode.mnU4 );
256 rOut.WriteInt32( rNode.mnDuration );
257 rOut.WriteInt32( rNode.mnNodeType );
258
259 return rOut;
260}
261
263 mrSolverContainer ( rSolverContainer ),
264 mrExSoundCollection ( rExSoundCollection ),
265 mnCurrentGroup(0)
266{
267}
268
269sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
270{
271 sal_Int16 nFill = xNode->getFill();
272 //#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
273 //#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.
274 if ((xNode->getType() == AnimationNodeType::ANIMATE)
275 ||(xNode->getType() == AnimationNodeType::SET)
276 ||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
277 {
278 if ( nFill == AnimationFill::DEFAULT )
279 return nFill;
280 }
281
282 if ( nFill == AnimationFill::DEFAULT )
283 {
284 nFill = nFillDefault;
285 }
286 if( nFill == AnimationFill::AUTO )
287 {
288 nFill = AnimationFill::REMOVE;
289 bool bIsIndefiniteTiming = true;
290 Any aAny = xNode->getDuration();
291 if( aAny.hasValue() )
292 {
293 Timing eTiming;
294 if( aAny >>= eTiming )
295 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
296 }
297 if ( bIsIndefiniteTiming )
298 {
299 aAny = xNode->getEnd();
300 if( aAny.hasValue() )
301 {
302 Timing eTiming;
303 if( aAny >>= eTiming )
304 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
305 }
306 if ( bIsIndefiniteTiming )
307 {
308 if ( !xNode->getRepeatCount().hasValue() )
309 {
310 aAny = xNode->getRepeatDuration();
311 if( aAny.hasValue() )
312 {
313 Timing eTiming;
314 if( aAny >>= eTiming )
315 bIsIndefiniteTiming = eTiming == Timing_INDEFINITE;
316 }
317 if ( bIsIndefiniteTiming )
318 nFill = AnimationFill::FREEZE;
319 }
320 }
321 }
322 }
323 return nFill;
324}
325
326void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm )
327{
328 Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
329 if( xNodeSupplier.is() )
330 {
331 const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() );
332 if( xRootNode.is() )
333 {
334 processAfterEffectNodes( xRootNode );
335 exportNode( rStrm, xRootNode, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
336 }
337 }
338}
339
340void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
341{
342 try
343 {
344 Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
345 Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_THROW );
346 while( xEnumeration->hasMoreElements() )
347 {
348 Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW );
349
350 Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY );
351 if ( xEnumerationAccess2.is() )
352 {
353 Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), css::uno::UNO_SET_THROW );
354 while( xEnumeration2->hasMoreElements() )
355 {
356 Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
357
358 Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
359 Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
360 while( xEnumeration3->hasMoreElements() )
361 {
362 Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
363
364 Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
365 Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_THROW );
366 while( xEnumeration4->hasMoreElements() )
367 {
368 Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW );
369
370 switch( xChildNode3->getType() )
371 {
372 // found an after effect
373 case AnimationNodeType::SET:
374 case AnimationNodeType::ANIMATECOLOR:
375 {
376 Reference< XAnimationNode > xMaster;
377
378 const Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
379 const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
380 [](const NamedValue& rProp) { return rProp.Name == "master-element"; });
381
382 if (p != aUserData.end())
383 p->Value >>= xMaster;
384
385 AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
386 maAfterEffectNodes.push_back( pAfterEffectNode );
387 }
388 break;
389 }
390 }
391 }
392 }
393 }
394 }
395 }
396 catch( Exception& )
397 {
398 TOOLS_WARN_EXCEPTION( "sd", "(@CL)AnimationExporter::processAfterEffectNodes()" );
399 }
400}
401
402bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
403{
404 return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
405 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
406}
407
408bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
409{
410 auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
411 [&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
412 if (aIter != maAfterEffectNodes.end())
413 {
414 xAfterEffectNode = (*aIter)->mxNode;
415 return true;
416 }
417
418 return false;
419}
420
421// check if this group only contain empty groups. this may happen when
422// after effect nodes are not exported at their original position
423bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const
424{
425 if( xNode.is() ) switch( xNode->getType() )
426 {
427 case AnimationNodeType::PAR :
428 case AnimationNodeType::SEQ :
429 case AnimationNodeType::ITERATE :
430 {
431 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
432 if( xEnumerationAccess.is() )
433 {
434 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
435 if( xEnumeration.is() )
436 {
437 while( xEnumeration->hasMoreElements() )
438 {
439 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
440 if( xChildNode.is() && !isEmptyNode( xChildNode ) )
441 return false;
442 }
443 }
444 }
445 }
446 break;
447
448 case AnimationNodeType::SET :
449 case AnimationNodeType::ANIMATECOLOR :
450 return isAfterEffectNode( xNode );
451 default:
452 return false;
453 }
454
455 return true;
456}
457
458void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > const & xNode_in, const sal_uInt16 nContainerRecType,
459 const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
460{
461 auto xNode = xNode_in;
462
463 if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
464 return;
465
466 if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
467 return;
468
469 if( nContainerRecType == DFF_msofbtAnimGroup )
471
472 bool bTakeBackInteractiveSequenceTimingForChild = false;
473 sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
474
475 Reference< XAnimationNode > xAudioNode;
476 static sal_uInt32 nAudioGroup;
477
478 {
479 bool bSkipChildren = false;
480 EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
481 switch( xNode->getType() )
482 {
483 case AnimationNodeType::CUSTOM :
484 {
485 exportAnimNode( rStrm, xNode, nFillDefault );
487 exportAnimEvent( rStrm, xNode );
488 exportAnimValue( rStrm, xNode, false );
489 }
490 break;
491
492 case AnimationNodeType::PAR :
493 {
494 exportAnimNode( rStrm, xNode, nFillDefault );
496 sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0;
497 if ( bTakeBackInteractiveSequenceTiming )
498 nFlags |= 0x40;
499 exportAnimEvent( rStrm, xNode, nFlags );
500 exportAnimValue( rStrm, xNode, nGroupLevel == 4 );
501 }
502 break;
503
504 case AnimationNodeType::SEQ :
505 {
506 exportAnimNode( rStrm, xNode, nFillDefault );
507 sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
508 sal_Int32 nFlags = 12;
509 if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
510 {
511 nFlags |= 0x20;
512 bTakeBackInteractiveSequenceTimingForChild = true;
513 }
514 exportAnimAction( rStrm, xNode );
515 exportAnimEvent( rStrm, xNode, nFlags );
516 exportAnimValue( rStrm, xNode, false );
517 }
518 break;
519
520 case AnimationNodeType::ITERATE :
521 {
522 {
523 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
524 AnimationNode aAnim;
526 aAnim.mnNodeType = 1;
527 // attribute Restart
528 switch( xNode->getRestart() )
529 {
530 default:
531 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
532 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
533 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
534 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
535 }
536 // attribute Fill
537 switch( xNode->getFill() )
538 {
539 default:
540 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
541 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
542 case AnimationFill::FREEZE : aAnim.mnFill = 2; break;
543 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
544 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
545 }
546 WriteAnimationNode( rStrm, aAnim );
547 }
548 exportIterate( rStrm, xNode );
550 exportAnimEvent( rStrm, xNode );
551 exportAnimValue( rStrm, xNode, false );
552 }
553 break;
554
555 case AnimationNodeType::ANIMATE :
556 {
557 exportAnimNode( rStrm, xNode, nFillDefault );
559 exportAnimEvent( rStrm, xNode );
560 exportAnimValue( rStrm, xNode, false );
561 exportAnimate( rStrm, xNode );
562 }
563 break;
564
565 case AnimationNodeType::SET :
566 {
567 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
568 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
569 {
570 exportAnimNode( rStrm, xNode, nFillDefault );
572 exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
573 exportAnimEvent( rStrm, xNode );
574 exportAnimValue( rStrm, xNode, false );
575 }
576 else
577 {
578 bSkipChildren = true;
579 }
580 }
581 break;
582
583 case AnimationNodeType::ANIMATEMOTION :
584 {
585 exportAnimNode( rStrm, xNode, nFillDefault );
587 exportAnimateMotion( rStrm, xNode );
588 exportAnimEvent( rStrm, xNode );
589 exportAnimValue( rStrm, xNode, false );
590 }
591 break;
592
593 case AnimationNodeType::ANIMATECOLOR :
594 {
595 bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
596 if( (nGroupLevel != 4) || !bIsAfterEffectNode )
597 {
598 if( bIsAfterEffectNode )
599 xNode = createAfterEffectNodeClone( xNode );
600
601 exportAnimNode( rStrm, xNode, nFillDefault );
603 exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
604 exportAnimEvent( rStrm, xNode );
605 exportAnimValue( rStrm, xNode, false );
606 }
607 else
608 {
609 bSkipChildren = true;
610 }
611 }
612 break;
613
614 case AnimationNodeType::ANIMATETRANSFORM :
615 {
616 exportAnimNode( rStrm, xNode, nFillDefault );
619 exportAnimEvent( rStrm, xNode );
620 exportAnimValue( rStrm, xNode, false );
621 }
622 break;
623
624 case AnimationNodeType::TRANSITIONFILTER :
625 {
626 exportAnimNode( rStrm, xNode, nFillDefault );
628 exportAnimEvent( rStrm, xNode );
629 exportAnimValue( rStrm, xNode, false );
631 }
632 break;
633
634 case AnimationNodeType::AUDIO : // #i58428#
635 {
636 exportAnimNode( rStrm, xNode, nFillDefault );
638
639 Reference< XAudio > xAudio( xNode, UNO_QUERY );
640 if( xAudio.is() )
641 {
642 Any aAny( xAudio->getSource() );
643 OUString aURL;
644
645 if ( ( aAny >>= aURL) && !aURL.isEmpty() )
646 {
647 sal_Int32 nU1 = 2;
648 sal_Int32 nTrigger = 3;
649 sal_Int32 nU3 = nAudioGroup;
650 sal_Int32 nBegin = 0;
651 {
653 {
655 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
656 }
657 }
658 nU1 = 1;
659 nTrigger = 0xb;
660 nU3 = 0;
661 {
663 {
665 rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
666 }
667 }
669 {
670 sal_uInt32 const nRefMode = 3;
671 sal_uInt32 const nRefType = 2;
672 sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
673 sal_Int32 const begin = -1;
674 sal_Int32 const end = -1;
675
676 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
677 rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
678 }
679 }
680 }
681 exportAnimValue( rStrm, xNode, false );
682 }
683 break;
684 }
685 if( !bSkipChildren )
686 {
687 // export after effect node if one exists for this node
688 Reference< XAnimationNode > xAfterEffectNode;
689 if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
690 {
691 exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
692 }
693
694 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
695 if( xEnumerationAccess.is() )
696 {
697 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
698 if( xEnumeration.is() )
699 {
700 while( xEnumeration->hasMoreElements() )
701 {
702 Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
703 if( xChildNode.is() )
704 {
705 if ( xChildNode->getType() == AnimationNodeType::AUDIO )
706 {
707 xAudioNode = xChildNode;
708 nAudioGroup = mnCurrentGroup;
709 }
710 else
711 exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
712 }
713 }
714 }
715 }
716 }
717 }
718 if ( xAudioNode.is() )
719 exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
720
721 if( xNode->getType() == AnimationNodeType::ITERATE )
722 aTarget = Any();
723}
724
725Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
726{
727 try
728 {
729 Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
730 Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
731
732 Any aEmpty;
733 xCloneNode->setBegin( aEmpty );
734
735 return xCloneNode;
736 }
737 catch( Exception& )
738 {
739 OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
740 }
741 return xNode;
742}
743
744bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
745{
746 // trying to get the nodetype
747 const Sequence< NamedValue > aUserData = xNode->getUserData();
748 for( const NamedValue& rProp : aUserData )
749 {
750 if ( rProp.Name == "node-type" )
751 {
752 if ( rProp.Value >>= nType )
753 return true;
754 }
755 }
756
757 return false;
758}
759
760void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
761 const sal_Int16 nFillDefault )
762{
763 EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
764 AnimationNode aAnim;
765
766 // attribute Restart
767 switch( xNode->getRestart() )
768 {
769 default:
770 case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break;
771 case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break;
772 case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break;
773 case AnimationRestart::NEVER : aAnim.mnRestart = 3; break;
774 }
775
776 switch( nFillDefault )
777 {
778 default:
779 case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
780 case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
781 case AnimationFill::FREEZE :
782 case AnimationFill::HOLD : aAnim.mnFill = 3; break;
783 case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
784 }
785 // attribute Duration
786 double fDuration = 0.0;
787 css::animations::Timing eTiming;
788 if ( xNode->getDuration() >>= eTiming )
789 {
790 if ( eTiming == Timing_INDEFINITE )
791 aAnim.mnDuration = -1;
792 }
793 else if ( xNode->getDuration() >>= fDuration )
794 {
795 aAnim.mnDuration = static_cast<sal_Int32>( fDuration * 1000.0 );
796 }
797 else
798 aAnim.mnDuration = -1;
799
800 // NodeType, NodeGroup
801 aAnim.mnNodeType = 1;
803 switch( xNode->getType() )
804 {
805 case AnimationNodeType::PAR :
807 [[fallthrough]];
808 case AnimationNodeType::SEQ :
809 {
810 sal_Int16 nType = 0;
811 if( GetNodeType( xNode, nType ) )
812 switch( nType )
813 {
814 case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
815 case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break;
816 }
817 }
818 break;
819
820 case AnimationNodeType::ANIMATE :
821 case AnimationNodeType::SET :
822
823 case AnimationNodeType::CUSTOM :
824 case AnimationNodeType::ITERATE :
825 case AnimationNodeType::ANIMATEMOTION :
826 case AnimationNodeType::ANIMATECOLOR :
827 case AnimationNodeType::ANIMATETRANSFORM :
828 {
831 }
832 break;
833
834 case AnimationNodeType::AUDIO :
835 {
838 }
839 break;
840
841 case AnimationNodeType::TRANSITIONFILTER :
842 {
845 }
846 break;
847 }
848
849 WriteAnimationNode( rStrm, aAnim );
850}
851
852void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
853{
854 // storing user data into pAny, to allow direct access later
855 memset( pAny, 0, nLen );
856 if ( !rUserData.hasElements() )
857 return;
858
859 for( const NamedValue& rProp : rUserData )
860 {
861 if ( rProp.Name == "node-type" )
862 {
863 pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
864 }
865 else if ( rProp.Name == "preset-class" )
866 {
867 pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
868 }
869 else if ( rProp.Name == "preset-id" )
870 {
871 pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
872 }
873 else if ( rProp.Name == "preset-sub-type" )
874 {
875 pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
876 }
877 else if ( rProp.Name == "master-element" )
878 {
879 pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
880 }
881 }
882}
883
884sal_uInt32 AnimationExporter::GetPresetID( std::u16string_view aPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
885{
886 sal_uInt32 nPresetId = 0;
887 bPresetId = false;
888
889 if ( o3tl::starts_with(aPreset, u"ppt_") )
890 {
891 size_t nLast = aPreset.rfind( '_' );
892 if ( ( nLast != std::u16string_view::npos ) && ( ( nLast + 1 ) < aPreset.size() ) )
893 {
894 std::u16string_view aNumber( aPreset.substr( nLast + 1 ) );
895 nPresetId = o3tl::toUInt32(aNumber);
896 bPresetId = true;
897 }
898 }
899 else
900 {
902 while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !o3tl::equalsAscii(aPreset, p->mpStrPresetId )) )
903 p++;
904
905 if( p->mpStrPresetId )
906 {
907 nPresetId = p->mnPresetId;
908 bPresetId = true;
909 }
910 }
911
912 return nPresetId;
913}
914
915sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
916{
917 sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
918
920
921 Reference< XAnimationNode > xMaster;
922
923 Any aMasterRel, aOverride, aRunTimeContext;
924
925 // storing user data into pAny, to allow direct access later
926 const Sequence< NamedValue > aUserData = xNode->getUserData();
927 const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
928 GetUserData( aUserData, pAny, sizeof( pAny ) );
929
930 if( pAny[ DFF_ANIM_AFTEREFFECT ] )
931 ( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
932
933 // calculate master-rel
934 if( xMaster.is() )
935 {
936 sal_Int32 nMasterRel = 2;
937 if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->getParent() ) )
938 nMasterRel = 0;
939
940 aMasterRel <<= nMasterRel;
941
942 pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel;
943
944 aOverride <<= sal_Int32(1);
945 pAny[ DFF_ANIM_OVERRIDE ] = &aOverride;
946
947 aRunTimeContext <<= sal_Int32(1);
948 pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext;
949 }
950
951 // the order is important
952 if ( pAny[ DFF_ANIM_NODE_TYPE ] )
953 {
954 if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType )
955 {
956 sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK;
957 switch( nNodeType )
958 {
959 case css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
960 case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
961 case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
962 case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
963 case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
964 case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
965 }
967 }
968 }
969 sal_uInt32 nPresetId = 0;
970 sal_uInt32 nPresetSubType = 0;
971 sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
972 sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
973 bool bPresetClass, bPresetId, bPresetSubType;
974 bPresetId = bPresetClass = bPresetSubType = false;
975
976 if ( pAny[ DFF_ANIM_PRESET_CLASS ] )
977 {
978 if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass )
979 {
980 sal_uInt8 nPPTPresetClass;
981 switch( nAPIPresetClass )
982 {
983 case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break;
984 case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break;
985 case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break;
986 case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break;
987 case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break;
988 case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break;
989 default :
990 nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
991 }
992 nPresetClass = nPPTPresetClass;
993 bPresetClass = true;
994 }
995 }
996 if ( pAny[ DFF_ANIM_PRESET_ID ] )
997 {
998 OUString sPreset;
999 if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
1000 nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
1001 }
1002
1003 if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
1004 {
1005 OUString sPresetSubType;
1006 if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
1007 {
1008 nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
1009 bPresetSubType = true;
1010 }
1011 }
1012 if ( bPresetId )
1014 if ( bPresetSubType )
1016 if ( bPresetClass )
1018
1019 if ( pAny[ DFF_ANIM_ID ] )
1020 {
1021 // TODO DFF_ANIM_ID
1022 }
1023
1024 if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
1025 {
1026 bool bAfterEffect = false;
1027 if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
1028 exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
1029 }
1030
1031 if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
1032 {
1033 sal_Int32 nRunTimeContext = 0;
1034 if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
1036 }
1037 if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
1038 {
1039 // TODO DFF_ANIM_ID
1040 }
1041
1042 if( !xMaster.is() )
1043 {
1044 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
1045 if( xColor.is() )
1046 {
1047
1048 bool bDirection = !xColor->getDirection();
1049 exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
1050 }
1051 }
1052
1053 if ( pAny[ DFF_ANIM_OVERRIDE ] )
1054 {
1055 sal_Int32 nOverride = 0;
1056 if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
1058 }
1059
1060 if ( pAny[ DFF_ANIM_MASTERREL ] )
1061 {
1062 sal_Int32 nMasterRel = 0;
1063 if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
1065 }
1066
1067/* todo
1068 Reference< XAudio > xAudio( xNode, UNO_QUERY );
1069 if( xAudio.is() )
1070 {
1071 sal_Int16 nEndAfterSlide = 0;
1072 nEndAfterSlide = xAudio->getEndAfterSlide();
1073 exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE );
1074 }
1075*/
1076 Reference< XAnimate > xAnim( xNode, UNO_QUERY );
1077 if( xAnim.is() )
1078 {
1079 // TODO: DFF_ANIM_TIMEFILTER
1080 }
1081 if ( pAny[ DFF_ANIM_EVENT_FILTER ] )
1082 {
1083 // TODO DFF_ANIM_EVENT_FILTER
1084 }
1085 if ( pAny[ DFF_ANIM_VOLUME ] )
1086 {
1087 // TODO DFF_ANIM_VOLUME
1088 }
1089 return nNodeType;
1090}
1091
1092bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
1093{
1094 bool bRet = false;
1095 if ( rAny.hasValue() )
1096 {
1097 switch( rAny.getValueType().getTypeClass() )
1098 {
1099 case css::uno::TypeClass_UNSIGNED_SHORT :
1100 case css::uno::TypeClass_SHORT :
1101 case css::uno::TypeClass_UNSIGNED_LONG :
1102 case css::uno::TypeClass_LONG :
1103 {
1104 sal_Int32 nVal = 0;
1105 if ( rAny >>= nVal )
1106 {
1108 bRet = true;
1109 }
1110 }
1111 break;
1112
1113 case css::uno::TypeClass_DOUBLE :
1114 {
1115 double fVal = 0.0;
1116 if ( rAny >>= fVal )
1117 {
1119 bRet = true;
1120 }
1121 }
1122 break;
1123 case css::uno::TypeClass_FLOAT :
1124 {
1125 float fVal = 0.0;
1126 if ( rAny >>= fVal )
1127 {
1128 if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
1129 {
1130 OUString aNumber( OUString::number( fVal ) );
1131 exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
1132 }
1133 else
1134 {
1136 bRet = true;
1137 }
1138 }
1139 }
1140 break;
1141 case css::uno::TypeClass_STRING :
1142 {
1143 OUString aStr;
1144 if ( rAny >>= aStr )
1145 {
1146 exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
1147 bRet = true;
1148 }
1149 }
1150 break;
1151 default:
1152 break;
1153 }
1154 }
1155 return bRet;
1156}
1157void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
1158{
1161 OUString aStr( rVal );
1162 if ( eTranslateMode != TRANSLATE_NONE )
1163 ImplTranslateAttribute( aStr, eTranslateMode );
1165}
1166
1167void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal )
1168{
1170 float fFloat = static_cast<float>(rVal);
1172 .WriteFloat( fFloat );
1173}
1174
1175void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
1176{
1179 .WriteUInt32( nVal );
1180}
1181
1182void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
1183{
1186 .WriteUChar( nVal );
1187}
1188
1189void AnimationExporter::writeZString( SvStream& rStrm, std::u16string_view aVal )
1190{
1191 for ( size_t i = 0; i < aVal.size(); i++ )
1192 rStrm.WriteUInt16( aVal[ i ] );
1193 rStrm.WriteUInt16( 0 );
1194}
1195
1196void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1197{
1199
1200 sal_Int32 const nConcurrent = 1;
1201 sal_Int32 const nNextAction = 1;
1202 sal_Int32 nEndSync = 0;
1203 sal_Int32 const nU4 = 0;
1204 sal_Int32 const nU5 = 3;
1205
1206 sal_Int16 nAnimationEndSync = 0;
1207 if ( xNode->getEndSync() >>= nAnimationEndSync )
1208 {
1209 if ( nAnimationEndSync == AnimationEndSync::ALL )
1210 nEndSync = 1;
1211 }
1212 rStrm.WriteInt32( nConcurrent )
1213 .WriteInt32( nNextAction )
1214 .WriteInt32( nEndSync )
1215 .WriteInt32( nU4 )
1216 .WriteInt32( nU5 );
1217
1218}
1219
1220// nFlags Bit 6 = fixInteractiveSequenceTiming (for child)
1221// nFlags Bit 5 = fixInteractiveSequenceTiming (for root)
1222// nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite
1223void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags )
1224{
1225 sal_uInt16 i;
1226 for ( i = 0; i < 4; i++ )
1227 {
1228 sal_Int32 nU1 = 0;
1229 sal_Int32 nTrigger = 0;
1230 sal_Int32 nU3 = 0;
1231 sal_Int32 nBegin = 0;
1232
1233 bool bCreateEvent = false;
1234 Any aSource;
1235
1236 switch( i )
1237 {
1238 case 0 :
1239 case 1 :
1240 {
1241 Any aAny;
1242 Event aEvent;
1243 css::animations::Timing eTiming;
1244 if ( i == 0 )
1245 {
1246 if ( nFlags & 0x20 )
1247 {
1248 // taking the first child
1249 Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW );
1250 Reference< XEnumeration > xE( xEA->createEnumeration(), css::uno::UNO_SET_THROW );
1251 if ( xE->hasMoreElements() )
1252 {
1253 Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY );
1254 aAny = xClickNode->getBegin();
1255 }
1256 }
1257 else if ( nFlags & 0x40 )
1258 {
1259 // begin has to be replaced with void, so don't do anything
1260 }
1261 else
1262 {
1263 aAny = xNode->getBegin();
1264 if ( nFlags & 0x10 ) // replace ON_NEXT with INDEFINITE
1265 {
1266 if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) )
1267 {
1268 eTiming = Timing_INDEFINITE;
1269 aAny <<= eTiming;
1270 }
1271 }
1272 }
1273 }
1274 else
1275 aAny = xNode->getEnd();
1276
1277 double fTiming = 0.0;
1278 if ( aAny >>= aEvent )
1279 {
1280 bCreateEvent = true;
1281 switch( aEvent.Trigger )
1282 {
1283 case EventTrigger::NONE : nTrigger = 0; break;
1284 case EventTrigger::ON_BEGIN : nTrigger = 1; break;
1285 case EventTrigger::ON_END : nTrigger = 2; break;
1286 case EventTrigger::BEGIN_EVENT : nTrigger = 3; break;
1287 case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break;
1288 case EventTrigger::ON_CLICK : nTrigger = 5; break;
1289 case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break;
1290 case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break;
1291 case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break;
1292 case EventTrigger::ON_NEXT : nTrigger = 9; break;
1293 case EventTrigger::ON_PREV : nTrigger = 10; break;
1294 case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break;
1295 }
1296 if ( aEvent.Offset.hasValue() )
1297 {
1298 if ( aEvent.Offset >>= eTiming )
1299 {
1300 if ( eTiming == Timing_INDEFINITE )
1301 nBegin = -1;
1302 }
1303 else if ( aEvent.Offset >>= fTiming )
1304 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1305 }
1306 aSource = aEvent.Source;
1307 }
1308 else if ( aAny >>= eTiming )
1309 {
1310 bCreateEvent = true;
1311 if ( eTiming == Timing_INDEFINITE )
1312 nBegin = -1;
1313 }
1314 else if ( aAny >>= fTiming )
1315 {
1316 bCreateEvent = true;
1317 nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
1318 }
1319 }
1320 break;
1321
1322 case 2 :
1323 {
1324 if ( nFlags & ( 1 << i ) )
1325 {
1326 bCreateEvent = true;
1327 nU1 = 1;
1328 nTrigger = 9;
1329 }
1330 }
1331 break;
1332 case 3 :
1333 {
1334 if ( nFlags & ( 1 << i ) )
1335 {
1336 bCreateEvent = true;
1337 nU1 = 1;
1338 nTrigger = 10;
1339 }
1340 }
1341 break;
1342 }
1343 if ( bCreateEvent )
1344 {
1345 EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
1346 {
1347 EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
1348 rStrm.WriteInt32( nU1 )
1349 .WriteInt32( nTrigger )
1350 .WriteInt32( nU3 )
1351 .WriteInt32( nBegin );
1352 }
1353 exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
1354 }
1355 }
1356}
1357
1358Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, std::u16string_view rAttributeName )
1359{
1360 OUString aDest;
1361 if ( rAttributeName == u"X"
1362 || rAttributeName == u"Y"
1363 || rAttributeName == u"Width"
1364 || rAttributeName == u"Height"
1365 )
1366 {
1367 OUString aStr;
1368 if ( rSourceValue >>= aStr )
1369 {
1371 aDest += aStr;
1372 }
1373 }
1374 else if ( rAttributeName == u"Rotate" // "r" or "style.rotation" ?
1375 || rAttributeName == u"Opacity"
1376 || rAttributeName == u"CharHeight"
1377 || rAttributeName == u"SkewX"
1378 )
1379 {
1380 double fNumber = 0.0;
1381 if ( rSourceValue >>= fNumber )
1382 aDest += OUString::number( fNumber );
1383 }
1384 else if ( rAttributeName == u"Color"
1385 || rAttributeName == u"FillColor" // "Fillcolor" or "FillColor" ?
1386 || rAttributeName == u"LineColor"
1387 || rAttributeName == u"CharColor"
1388 )
1389 {
1390 sal_Int32 nColor = 0;
1391 Sequence< double > aHSL( 3 );
1392 OUString aP( "," );
1393 if ( rSourceValue >>= aHSL )
1394 {
1395 aDest += "hsl("
1396 + OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
1397 + aP
1398 + OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
1399 + aP
1400 + OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
1401 + ")";
1402 }
1403 else if ( rSourceValue >>= nColor )
1404 {
1405 aDest += "rgb("
1406 + OUString::number( static_cast<sal_Int8>(nColor) )
1407 + aP
1408 + OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
1409 + aP
1410 + OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
1411 + ")";
1412 }
1413 }
1414 else if ( rAttributeName == u"FillStyle" )
1415 {
1416 css::drawing::FillStyle eFillStyle;
1417 if ( rSourceValue >>= eFillStyle )
1418 {
1419 if ( eFillStyle == css::drawing::FillStyle_NONE )
1420 aDest += "none"; // ?
1421 else
1422 aDest += "solid";
1423 }
1424 }
1425 else if (rAttributeName == u"FillOn")
1426 {
1427 bool bFillOn;
1428 if ( rSourceValue >>= bFillOn )
1429 {
1430 if ( bFillOn )
1431 aDest += "true";
1432 else
1433 aDest += "false";
1434 }
1435 }
1436 else if ( rAttributeName == u"LineStyle" )
1437 {
1438 css::drawing::LineStyle eLineStyle;
1439 if ( rSourceValue >>= eLineStyle )
1440 {
1441 if ( eLineStyle == css::drawing::LineStyle_NONE )
1442 aDest += "false";
1443 else
1444 aDest += "true";
1445 }
1446 }
1447 else if ( rAttributeName == u"CharWeight" )
1448 {
1449 float fFontWeight = 0.0;
1450 if ( rSourceValue >>= fFontWeight )
1451 {
1452 if ( fFontWeight == css::awt::FontWeight::BOLD )
1453 aDest += "bold";
1454 else
1455 aDest += "normal";
1456 }
1457 }
1458 else if ( rAttributeName == u"CharUnderline" )
1459 {
1460 sal_Int16 nFontUnderline = 0;
1461 if ( rSourceValue >>= nFontUnderline )
1462 {
1463 if ( nFontUnderline == css::awt::FontUnderline::NONE )
1464 aDest += "false";
1465 else
1466 aDest += "true";
1467 }
1468 }
1469 else if ( rAttributeName == u"CharPosture" )
1470 {
1471 css::awt::FontSlant eFontSlant;
1472 if ( rSourceValue >>= eFontSlant )
1473 {
1474 if ( eFontSlant == css::awt::FontSlant_ITALIC )
1475 aDest += "italic";
1476 else
1477 aDest += "normal"; // ?
1478 }
1479 }
1480 else if ( rAttributeName == u"Visibility" )
1481 {
1482 bool bVisible = true;
1483 if ( rSourceValue >>= bVisible )
1484 {
1485 if ( bVisible )
1486 aDest += "visible";
1487 else
1488 aDest += "hidden";
1489 }
1490 }
1491 Any aRet;
1492 if ( !aDest.isEmpty() )
1493 aRet <<= aDest;
1494 else
1495 aRet = rSourceValue;
1496 return aRet;
1497}
1498
1499void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
1500{
1501 Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
1502 if( !xSet.is() )
1503 return;
1504
1505 EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
1506 {
1507 EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
1508 sal_uInt32 const nId1 = 1; // ??
1509 sal_uInt32 const nId2 = 1; // ??
1510 rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
1511 }
1512 Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
1513 if ( aConvertedValue.hasValue() )
1514 exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
1515 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
1516}
1517
1518sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( std::u16string_view rAttributeName )
1519{
1520 sal_uInt32 nValueType = 0;
1521
1522 struct Entry
1523 {
1524 const char* pName;
1526 };
1527 static const Entry lcl_attributeMap[] =
1528 {
1529 { "charcolor", 2 },
1530 { "charfontname", 0 },
1531 { "charheight", 1 },
1532 { "charposture", 0 },
1533 // TODO(Q1): This should prolly be changed in PPT import
1534 // { "charrotation", ATTRIBUTE_CHAR_ROTATION },
1535 { "charrotation", 1 },
1536 { "charunderline", 0 },
1537 { "charweight", 0 },
1538 { "color", 2 },
1539 { "dimcolor", 2 },
1540 { "fillcolor", 2 },
1541 { "fillstyle", 0 },
1542 { "height", 1 },
1543 { "linecolor", 2 },
1544 { "linestyle", 0 },
1545 { "opacity", 0 },
1546 { "rotate", 1 },
1547 { "skewx", 1 },
1548 { "skewy", 1 },
1549 { "visibility", 1 },
1550 { "width", 1 },
1551 { "x", 1 },
1552 { "y", 1 },
1553 { nullptr, 0 }
1554 };
1555 const Entry* pPtr = &lcl_attributeMap[ 0 ];
1556 while( pPtr->pName )
1557 {
1558 if ( o3tl::equalsIgnoreAsciiCase( rAttributeName, pPtr->pName ) )
1559 {
1560 nValueType = pPtr->nType;
1561 break;
1562 }
1563 pPtr++;
1564 }
1565 DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" );
1566 return nValueType;
1567}
1568
1569void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1570{
1571 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1572 if ( !xAnimate.is() )
1573 return;
1574
1575 Any aBy ( xAnimate->getBy() );
1576 Any aFrom( xAnimate->getFrom() );
1577 Any aTo ( xAnimate->getTo() );
1578
1579 EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 );
1580 {
1581 EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData );
1582 sal_uInt32 nBits = 0x38;
1583 sal_Int16 nTmp = xAnimate->getCalcMode();
1584 sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0;
1585 sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
1586
1587 if ( aBy.hasValue() )
1588 nBits |= 1;
1589 if ( aFrom.hasValue() )
1590 nBits |= 2;
1591 if ( aTo.hasValue() )
1592 nBits |= 4;
1593
1594 rStrm.WriteUInt32( nCalcMode )
1595 .WriteUInt32( nBits )
1596 .WriteUInt32( nValueType );
1597 }
1598 if ( aBy.hasValue() )
1600 if ( aFrom.hasValue() )
1602 if ( aTo.hasValue() )
1604
1605 exportAnimateKeyPoints( rStrm, xAnimate );
1606 exportAnimateTarget( rStrm, xNode );
1607}
1608
1609void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType )
1610{
1611 EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 );
1612 Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
1613 if ( !xAnimate.is() )
1614 return;
1615
1616 {
1617 EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 );
1618 // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
1619 // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
1620 // nAccumulate 0 = none, 1 = always
1621 // nTransformType 0: "property" else "image"
1622 sal_uInt32 nBits = 0;
1623 sal_uInt32 nAdditive = 0;
1624 sal_uInt32 nAccumulate = 0;
1625 sal_uInt32 const nTransformType = 0;
1626 if ( xAnimate.is() )
1627 {
1628 if ( !xAnimate->getAttributeName().isEmpty() )
1629 nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written
1630 sal_Int16 nAdditiveMode = xAnimate->getAdditive();
1631 if ( nAdditiveMode != AnimationAdditiveMode::BASE )
1632 {
1633 nBits |= 1;
1634 switch( nAdditiveMode )
1635 {
1636 case AnimationAdditiveMode::SUM : nAdditive = 1; break;
1637 case AnimationAdditiveMode::REPLACE : nAdditive = 2; break;
1638 case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break;
1639 case AnimationAdditiveMode::NONE : nAdditive = 4; break;
1640 }
1641 }
1642 if ( xAnimate->getAccumulate() )
1643 {
1644 nBits |= 2;
1645 nAccumulate = 1;
1646 }
1647 }
1648 rStrm.WriteUInt32( nBits )
1649 .WriteUInt32( nAdditive )
1650 .WriteUInt32( nAccumulate )
1651 .WriteUInt32( nTransformType );
1652 }
1653 if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
1654 {
1655 EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
1656 OUString aAttributeName( xAnimate->getAttributeName() );
1657 if ( nForceAttributeNames )
1658 {
1659 if( nForceAttributeNames == 1 )
1660 {
1661 aAttributeName = "r";
1662 }
1663 }
1664 sal_Int32 nIndex = 0;
1665 do
1666 {
1667 OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) );
1669 }
1670 while ( nIndex >= 0 );
1671 }
1672
1673 if( nAfterEffectType != AFTEREFFECT_NONE )
1674 {
1677 if( nAfterEffectType == AFTEREFFECT_COLOR )
1678 {
1681 }
1682 }
1683 exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
1684}
1685
1686Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
1687{
1688 Reference< XShape > xShape;
1689 rAny >>= xShape;
1690
1691 rParagraphTarget = false;
1692
1693 if( xShape.is() )
1694 return xShape;
1695
1696 ParagraphTarget aParaTarget;
1697 if( rAny >>= aParaTarget )
1698 xShape = aParaTarget.Shape;
1699 if ( !xShape.is() )
1700 return xShape;
1701
1702 // now calculating the character range for the paragraph
1703 sal_Int16 nParagraph = aParaTarget.Paragraph;
1704 Reference< XSimpleText > xText( xShape, UNO_QUERY );
1705 if ( !xText.is() )
1706 return xShape;
1707
1708 rParagraphTarget = true;
1709 Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
1710 if ( !xTextParagraphEnumerationAccess.is() )
1711 return xShape;
1712
1713 Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
1714 if ( !xTextParagraphEnumeration.is() )
1715 return xShape;
1716
1717 sal_Int16 nCurrentParagraph;
1718 rBegin = rEnd = nCurrentParagraph = 0;
1719 while ( xTextParagraphEnumeration->hasMoreElements() )
1720 {
1721 Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
1722 if ( xTextRange.is() )
1723 {
1724 OUString aParaText( xTextRange->getString() );
1725 sal_Int32 nLength = aParaText.getLength() + 1;
1726 rEnd += nLength;
1727 if ( nCurrentParagraph == nParagraph )
1728 break;
1729 nCurrentParagraph++;
1730 rBegin += nLength;
1731 }
1732 }
1733
1734 return xShape;
1735}
1736
1737void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
1738{
1739 sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
1740 sal_Int32 begin = -1;
1741 sal_Int32 end = -1;
1742 bool bParagraphTarget;
1743
1744 Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
1745
1746 if( bParagraphTarget )
1747 nRefMode = 2;
1748
1749 if ( !(xShape.is() || bCreate2b01Atom) )
1750 return;
1751
1752 EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
1753 if ( xShape.is() )
1754 {
1755 EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
1756
1757 sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
1758 sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
1759
1760 rStrm.WriteUInt32( nRefMode )
1761 .WriteUInt32( nRefType )
1762 .WriteUInt32( nRefId )
1763 .WriteInt32( begin )
1764 .WriteInt32( end );
1765 }
1766 if ( bCreate2b01Atom )
1767 {
1768 EscherExAtom a2b01Atom( rStrm, 0x2b01 );
1769 rStrm.WriteUInt32( 1 ); // ?
1770 }
1771}
1772
1773void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate )
1774{
1775 Sequence< double > aKeyTimes( xAnimate->getKeyTimes() );
1776 Sequence< Any > aValues( xAnimate->getValues() );
1777 OUString aFormula( xAnimate->getFormula() );
1778 if ( !aKeyTimes.hasElements() )
1779 return;
1780
1782 sal_Int32 i;
1783 for ( i = 0; i < aKeyTimes.getLength(); i++ )
1784 {
1785 {
1786 EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
1787 sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
1788 rStrm.WriteInt32( nKeyTime );
1789 }
1790 Any aAny[ 2 ];
1791 if ( aValues[ i ].hasValue() )
1792 {
1793 ValuePair aPair;
1794 if ( aValues[ i ] >>= aPair )
1795 {
1796 aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() );
1797 aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() );
1798 }
1799 else
1800 {
1801 aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() );
1802 }
1803 if ( !i && !aFormula.isEmpty() )
1804 {
1806 aAny[ 1 ] <<= aFormula;
1807 }
1808 exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE );
1809 exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE );
1810 }
1811 }
1812}
1813
1814void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const bool bExportAlways )
1815{
1816 Any aAny;
1817 // repeat count (0)
1818 double fRepeat = 0.0;
1819 float fRepeatCount = 0.0;
1820 css::animations::Timing eTiming;
1821 aAny = xNode->getRepeatCount();
1822 if ( aAny >>= eTiming )
1823 {
1824 if ( eTiming == Timing_INDEFINITE )
1825 fRepeatCount = (float(3.40282346638528860e+38));
1826 }
1827 else if ( aAny >>= fRepeat )
1828 fRepeatCount = static_cast<float>(fRepeat);
1829 if ( fRepeatCount != 0.0 )
1830 {
1832 sal_uInt32 const nType = 0;
1834 .WriteFloat( fRepeatCount );
1835 }
1836 // accelerate (3)
1837 float fAccelerate = static_cast<float>(xNode->getAcceleration());
1838 if ( bExportAlways || ( fAccelerate != 0.0 ) )
1839 {
1841 sal_uInt32 const nType = 3;
1843 .WriteFloat( fAccelerate );
1844 }
1845
1846 // decelerate (4)
1847 float fDecelerate = static_cast<float>(xNode->getDecelerate());
1848 if ( bExportAlways || ( fDecelerate != 0.0 ) )
1849 {
1851 sal_uInt32 const nType = 4;
1853 .WriteFloat( fDecelerate );
1854 }
1855
1856 // autoreverse (5)
1857 bool bAutoReverse = xNode->getAutoReverse();
1858 if ( bExportAlways || bAutoReverse )
1859 {
1861 sal_uInt32 const nType = 5;
1862 sal_uInt32 nVal = bAutoReverse ? 1 : 0;
1864 .WriteUInt32( nVal );
1865 }
1866}
1867
1868void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1869{
1870 Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
1871 if ( !xFilter.is() )
1872 return;
1873
1875 {
1876 EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
1877 sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
1878 // bit 1 -> use nTransition
1879
1880 sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
1881 rStrm.WriteUInt32( nBits )
1882 .WriteUInt32( nTransition );
1883 }
1884 const char* pFilter = FindTransitionName( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() );
1885 if ( pFilter )
1886 {
1887 const OUString aStr( OUString::createFromAscii( pFilter ) );
1889 }
1890 exportAnimateTarget( rStrm, xNode );
1891}
1892
1893void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1894{
1895 Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
1896 if ( !xMotion.is() )
1897 return;
1898
1900 {
1901 { //SJ: Ignored from import filter
1902 EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
1903 sal_uInt32 const nBits = 0x98;
1904 sal_uInt32 const nOrigin = 0x2;
1905 float const fByX = 100.0; // nBits&1
1906 float const fByY = 100.0; // nBits&1
1907 float const fFromX = 0.0; // nBits&2
1908 float const fFromY = 0.0; // nBits&2
1909 float const fToX = 100.0; // nBits&4
1910 float const fToY = 100.0; // nBits&4
1911 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
1912 }
1913
1914 OUString aStr;
1915 if ( xMotion->getPath() >>= aStr )
1916 {
1917 if ( !aStr.isEmpty() )
1919 }
1920 exportAnimateTarget( rStrm, xNode );
1921 }
1922}
1923
1924void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
1925{
1926 Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
1927 if ( !xTransform.is() )
1928 return;
1929
1930 if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
1931 {
1933 {
1934 EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
1935 sal_uInt32 nBits = 0;
1936 sal_uInt32 const nZoomContents = 1;
1937 float fByX = 100.0;
1938 float fByY = 100.0;
1939 float fFromX = 0.0;
1940 float fFromY = 0.0;
1941 float fToX = 100.0;
1942 float fToY = 100.0;
1943
1944 double fX = 0.0, fY = 0.0;
1945 ValuePair aPair;
1946 if ( xTransform->getBy() >>= aPair )
1947 {
1948 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1949 {
1950 nBits |= 1;
1951 fByX = static_cast<float>( fX * 100 );
1952 fByY = static_cast<float>( fY * 100 );
1953 }
1954 }
1955 if ( xTransform->getFrom() >>= aPair )
1956 {
1957 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1958 {
1959 nBits |= 2;
1960 fFromX = static_cast<float>( fX * 100 );
1961 fFromY = static_cast<float>( fY * 100 );
1962 }
1963 }
1964 if( xTransform->getTo() >>= aPair )
1965 {
1966 if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
1967 {
1968 nBits |= 4;
1969 fToX = static_cast<float>( fX * 100 );
1970 fToY = static_cast<float>( fY * 100 );
1971 }
1972 }
1973
1974 // TODO: ZoomContents:
1975 //if( nBits & 8 )
1976 //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
1977
1978 rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nZoomContents );
1979 }
1980 exportAnimateTarget( rStrm, xNode );
1981 }
1982 else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE )
1983 {
1985 {
1986 EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData );
1987 sal_uInt32 nBits = 0;
1988 sal_uInt32 const nU1 = 0;
1989 float fBy = 360.0;
1990 float fFrom = 0.0;
1991 float fTo = 360.0;
1992
1993 double fVal = 0.0;
1994 if ( xTransform->getBy() >>= fVal )
1995 {
1996 nBits |= 1;
1997 fBy = static_cast<float>(fVal);
1998 }
1999 if ( xTransform->getFrom() >>= fVal )
2000 {
2001 nBits |= 2;
2002 fFrom = static_cast<float>(fVal);
2003 }
2004 if ( xTransform->getTo() >>= fVal )
2005 {
2006 nBits |= 4;
2007 fTo = static_cast<float>(fVal);
2008 }
2009 rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
2010 }
2011 exportAnimateTarget( rStrm, xNode, 1 );
2012 }
2013}
2014
2015bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
2016{
2017 bool bIsColor = true;
2018
2019 rMode = 0;
2020 if ( nColorSpace == AnimationColorSpace::HSL )
2021 rMode = 1;
2022
2023 sal_Int32 nColor = 0;
2024 Sequence< double > aHSL( 3 );
2025 if ( rAny >>= nColor ) // RGB color
2026 {
2027 rA = static_cast<sal_uInt8>( nColor >> 16 );
2028 rB = static_cast<sal_uInt8>( nColor >> 8 );
2029 rC = static_cast<sal_uInt8>(nColor);
2030 }
2031 else if ( rAny >>= aHSL ) // HSL
2032 {
2033 rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
2034 rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
2035 rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
2036 }
2037 else
2038 bIsColor = false;
2039 return bIsColor;
2040}
2041
2042void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
2043{
2044 Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
2045 if ( !xColor.is() )
2046 return;
2047
2049 {
2050 EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData );
2051 sal_uInt32 nBits = 8;
2052
2053 sal_Int32 nByMode, nByA, nByB, nByC;
2054 nByMode = nByA = nByB = nByC = 0;
2055
2056 sal_Int32 nFromMode, nFromA, nFromB, nFromC;
2057 nFromMode = nFromA = nFromB = nFromC = 0;
2058
2059 sal_Int32 nToMode, nToA, nToB, nToC;
2060 nToMode = nToA = nToB = nToC = 0;
2061
2062 sal_Int16 nColorSpace = xColor->getColorInterpolation();
2063
2064 Any aAny( xColor->getBy() );
2065 if ( aAny.hasValue() )
2066 {
2067 if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) )
2068 nBits |= 0x11;
2069 }
2070 aAny = xColor->getFrom();
2071 if ( aAny.hasValue() )
2072 {
2073 if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) )
2074 nBits |= 0x12;
2075 }
2076 aAny = xColor->getTo();
2077 if ( aAny.hasValue() )
2078 {
2079 if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) )
2080 nBits |= 0x14;
2081 }
2082 rStrm .WriteUInt32( nBits )
2083 .WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
2084 .WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
2085 .WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
2086 }
2087 exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
2088}
2089
2090void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
2091{
2092 Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
2093 if ( !xIterate.is() )
2094 return;
2095
2096 EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
2097
2098 float fInterval = 10.0;
2099 sal_Int32 nTextUnitEffect = 0;
2100 sal_Int32 const nU1 = 1;
2101 sal_Int32 const nU2 = 1;
2102 sal_Int32 const nU3 = 0xe;
2103
2104 sal_Int16 nIterateType = xIterate->getIterateType();
2105 switch( nIterateType )
2106 {
2107 case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
2108 case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
2109 }
2110
2111 fInterval = static_cast<float>(xIterate->getIterateInterval());
2112
2113 // convert interval from absolute to percentage
2114 double fDuration = 0.0;
2115
2116 Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
2117 if( xEnumerationAccess.is() )
2118 {
2119 Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
2120 if( xEnumeration.is() )
2121 {
2122 while( xEnumeration->hasMoreElements() )
2123 {
2124 Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
2125 if( xChildNode.is() )
2126 {
2127 double fChildBegin = 0.0;
2128 double fChildDuration = 0.0;
2129 xChildNode->getBegin() >>= fChildBegin;
2130 xChildNode->getDuration() >>= fChildDuration;
2131
2132 fChildDuration += fChildBegin;
2133 if( fChildDuration > fDuration )
2134 fDuration = fChildDuration;
2135 }
2136 }
2137 }
2138 }
2139
2140 if( fDuration )
2141 fInterval = static_cast<float>(100.0 * fInterval / fDuration);
2142
2143 rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
2144 aTarget = xIterate->getTarget();
2145}
2146
2147} // namespace ppt;
2148
2149/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
PropFlags nPropertyId
const char * pName
AnyEventRef aEvent
sal_uInt32 GetShapeId(const css::uno::Reference< css::drawing::XShape > &rShape) const
SvStream & WriteInt32(sal_Int32 nInt32)
SvStream & WriteUChar(unsigned char nChar)
SvStream & WriteUInt16(sal_uInt16 nUInt16)
SvStream & WriteUInt32(sal_uInt32 nUInt32)
SvStream & WriteFloat(float nFloat)
static void GetUserData(const css::uno::Sequence< css::beans::NamedValue > &rUserData, const css::uno::Any **pAny, std::size_t nLen)
static void writeZString(SvStream &rStrm, std::u16string_view aVal)
ppt::ExSoundCollection & mrExSoundCollection
void doexport(const css::uno::Reference< css::drawing::XDrawPage > &xPage, SvStream &rStrm)
static bool GetNodeType(const css::uno::Reference< css::animations::XAnimationNode > &xNode, sal_Int16 &nType)
void exportAnimateTarget(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, const sal_uInt32 nForceAttributeName=0, int nAfterEffectType=AFTEREFFECT_NONE)
static sal_Int16 GetFillMode(const css::uno::Reference< css::animations::XAnimationNode > &xNode, const sal_Int16 nFillDefault)
void exportAnimate(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static css::uno::Any convertAnimateValue(const css::uno::Any &rSource, std::u16string_view rAttributeName)
static sal_uInt32 GetPresetID(std::u16string_view aPreset, sal_uInt32 nAPIPresetClass, bool &bPresetId)
const EscherSolverContainer & mrSolverContainer
static sal_Int16 exportAnimPropertySet(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
if available exportAnimPropertySet
static bool getColorAny(const css::uno::Any &rAny, const sal_Int16 nColorSpace, sal_Int32 &rMode, sal_Int32 &rA, sal_Int32 &rB, sal_Int32 &rC)
static void exportAnimNode(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, const sal_Int16 nFillDefault)
static void exportAnimPropertyString(SvStream &rStrm, const sal_uInt16 nPropertyId, const OUString &rVal, const TranslateMode eTranslateMode)
void exportNode(SvStream &rStrm, css::uno::Reference< css::animations::XAnimationNode > const &xNode, const sal_uInt16 nContainerRecType, const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFillDefault)
void exportAnimateSet(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, int nAfterEffectType)
static void exportAnimateKeyPoints(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimate > &xAnimate)
void exportAnimateTransform(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static sal_uInt32 TranslatePresetSubType(const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType)
bool isAfterEffectNode(const css::uno::Reference< css::animations::XAnimationNode > &xNode) const
static const char * FindTransitionName(const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection)
AnimationExporter(const EscherSolverContainer &rSolverContainer, ppt::ExSoundCollection &rExSoundCollection)
void exportAnimateTargetElement(SvStream &rStrm, const css::uno::Any &rAny, const bool bCreate2b01Atom)
bool isEmptyNode(const css::uno::Reference< css::animations::XAnimationNode > &xNode) const
void exportTransitionFilter(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static void exportAnimValue(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, const bool bExportAlways)
void exportIterate(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
void exportAnimateColor(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, int nAfterEffectType)
void processAfterEffectNodes(const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static css::uno::Reference< css::animations::XAnimationNode > createAfterEffectNodeClone(const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static void exportAnimPropertyByte(SvStream &rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal)
static css::uno::Reference< css::drawing::XShape > getTargetElementShape(const css::uno::Any &rAny, sal_Int32 &rBegin, sal_Int32 &rEnd, bool &rParagraphTarget)
static void exportAnimAction(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
static void exportAnimPropertyuInt32(SvStream &rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal)
static void exportAnimPropertyFloat(SvStream &rStrm, const sal_uInt16 nPropertyId, const double &rVal)
void exportAnimEvent(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode, const sal_Int32 nFlags=0)
static bool exportAnimProperty(SvStream &rStrm, const sal_uInt16 nPropertyId, const css::uno::Any &rAny, const TranslateMode eTranslateMode)
void exportAnimateMotion(SvStream &rStrm, const css::uno::Reference< css::animations::XAnimationNode > &xNode)
std::vector< AfterEffectNodePtr > maAfterEffectNodes
bool hasAfterEffectNode(const css::uno::Reference< css::animations::XAnimationNode > &xNode, css::uno::Reference< css::animations::XAnimationNode > &xAfterEffectNode) const
static sal_uInt32 GetValueTypeForAttributeName(std::u16string_view rAttributeName)
sal_uInt32 GetId(const OUString &)
#define DBG_ASSERT(sCon, aError)
#define TOOLS_WARN_EXCEPTION(area, stream)
URL aURL
float u
sal_Int32 nIndex
void * p
Environment aTo
Environment aFrom
aStr
@ Exception
int i
void SvStream & rStrm
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
enumrange< T >::Iterator begin(enumrange< T >)
sal_uInt32 toUInt32(std::u16string_view str, sal_Int16 radix=10)
bool equalsAscii(std::u16string_view s1, std::string_view s2)
const ImplAttributeNameConversion * getAttributeConversionList()
end
const sal_Int32 mso_Anim_GroupType_MEDIA
SvStream & WriteAnimationNode(SvStream &rOut, AnimationNode const &rNode)
const int AFTEREFFECT_NONE
static void ImplTranslateAttribute(OUString &rString, const TranslateMode eTranslateMode)
const sal_Int32 mso_Anim_Behaviour_ANIMATION
const int AFTEREFFECT_COLOR
const sal_Int32 mso_Anim_GroupType_PAR
const sal_Int32 mso_Anim_GroupType_SEQ
const sal_Int32 mso_Anim_Behaviour_FILTER
const int AFTEREFFECT_SET
std::shared_ptr< AfterEffectNode > AfterEffectNodePtr
const sal_Int32 mso_Anim_GroupType_NODE
sal_uInt32 TranslateMode
#define DFF_ANIM_RUNTIMECONTEXT
#define DFF_ANIM_PRESS_CLASS_OLE_ACTION
#define DFF_msofbtAnimateRotationData
#define DFF_msofbtAnimAction
#define DFF_msofbtAnimateMotionData
#define DFF_msofbtAnimateTargetSettings
#define DFF_msofbtAnimPropertySet
#define DFF_msofbtAnimateFilterData
#define DFF_msofbtAnimateSetData
#define DFF_msofbtAnimValue
#define DFF_ANIM_DIRECTION
#define DFF_msofbtAnimKeyPoints
#define DFF_msofbtAnimSubGoup
#define DFF_ANIM_PRESS_CLASS_USER_DEFINED
#define DFF_ANIM_NODE_TYPE_ON_CLICK
#define DFF_ANIM_EVENT_FILTER
#define DFF_msofbtAnimateTarget
#define DFF_ANIM_PRESET_SUB_TYPE
#define DFF_ANIM_NODE_TYPE
#define DFF_ANIM_PROPERTY_ID_COUNT
#define DFF_ANIM_PATH_EDIT_MODE
#define DFF_ANIM_AFTEREFFECT
#define DFF_msofbtAnimReference
#define DFF_msofbtAnimGroup
#define DFF_msofbtAnimateAttributeNames
#define DFF_msofbtAnimateTargetElement
#define DFF_msofbtAnimIteration
#define DFF_ANIM_NODE_TYPE_WITH_PREVIOUS
#define DFF_ANIM_OVERRIDE
#define DFF_msofbtAnimKeyTime
#define DFF_ANIM_PRESET_CLASS
#define DFF_ANIM_MASTERREL
#define DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ
#define DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS
#define DFF_msofbtAnimTrigger
#define DFF_msofbtAnimAttributeValue
#define DFF_ANIM_PRESS_CLASS_EXIT
#define DFF_msofbtAnimNode
#define DFF_ANIM_PRESS_CLASS_EMPHASIS
#define DFF_ANIM_PROP_TYPE_UNISTRING
#define DFF_msofbtAnimateData
#define DFF_ANIM_NODE_TYPE_TIMING_ROOT
#define DFF_msofbtAnimateScale
#define DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE
#define DFF_msofbtAnimEvent
#define DFF_msofbtAnimateScaleData
#define DFF_ANIM_VOLUME
#define DFF_msofbtAnimateSet
#define DFF_ANIM_PRESET_ID
#define DFF_msofbtAnimateRotation
#define DFF_ANIM_PROP_TYPE_BYTE
#define DFF_ANIM_PRESS_CLASS_MOTIONPATH
#define DFF_ANIM_PROP_TYPE_INT32
#define DFF_ANIM_ID
#define DFF_ANIM_PRESS_CLASS_ENTRANCE
#define DFF_msofbtAnimateMotion
#define DFF_ANIM_PROP_TYPE_FLOAT
#define DFF_msofbtAnimateFilter
#define DFF_ANIM_PRESS_CLASS_MEDIACALL
#define DFF_msofbtAnimate
#define DFF_msofbtAnimateColorData
#define DFF_msofbtAnimateColor
#define TRANSLATE_VALUE
#define TRANSLATE_NUMBER_TO_STRING
#define TRANSLATE_MEASURE
#define TRANSLATE_NONE
#define TRANSLATE_ATTRIBUTE
QPRO_FUNC_TYPE nType
static const convert_subtype * getList()
static const preset_mapping * getList()
static const transition * getList()
this atom is the first entry in each animation group
sal_Int32 mnNodeType
see mso_Anim_Behaviour_?
sal_Int32 mnFill
see mso_Anim_Fill_?
sal_Int32 mnGroupType
see mso_Anim_GroupType_?
sal_Int32 mnRestart
see mso_Anim_Restart_?
sal_Int32 mnDuration
duration of this group in 1000th seconds
bool bVisible
unsigned char sal_uInt8
signed char sal_Int8
sal_Int32 nLength