tdf#131098 docx export: write fill property of graphic
[LibreOffice.git] / sd / source / filter / ppt / ppt97animations.cxx
blobdb3a960a78d41c364351a5182b0d05a3c1d0aaf7
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 "ppt97animations.hxx"
22 #include <svx/svdobj.hxx>
23 #include <sdpage.hxx>
24 #include <tools/stream.hxx>
25 #include <svx/unoapi.hxx>
26 #include <sal/log.hxx>
27 #include <osl/diagnose.h>
28 #include <CustomAnimationPreset.hxx>
29 #include <com/sun/star/presentation/TextAnimationType.hpp>
30 #include <com/sun/star/presentation/EffectNodeType.hpp>
31 #include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
33 using namespace ::com::sun::star;
35 void Ppt97AnimationInfoAtom::ReadStream( SvStream& rIn )
37 sal_uInt32 nTmp;
38 rIn.ReadUInt32( nTmp );
39 nDimColor = Color(ColorTransparency, nTmp);
40 rIn.ReadUInt32( nFlags );
41 rIn.ReadUInt32( nSoundRef );
42 rIn.ReadInt32( nDelayTime );
43 rIn.ReadUInt16( nOrderID );
44 rIn.ReadUInt16( nSlideCount );
45 rIn.ReadUChar( nBuildType );
46 rIn.ReadUChar( nFlyMethod );
47 rIn.ReadUChar( nFlyDirection );
48 rIn.ReadUChar( nAfterEffect );
49 rIn.ReadUChar( nSubEffect );
50 rIn.ReadUChar( nOLEVerb );
51 rIn.ReadUChar( nUnknown1 );
52 rIn.ReadUChar( nUnknown2 );
55 Ppt97Animation::Ppt97Animation( SvStream& rInputStream )
56 : m_aAtom()
57 , m_bDirtyCache(true)
58 , m_bHasSpecialDuration(false)
59 , m_fDurationInSeconds(0.001)
61 m_aAtom.ReadStream( rInputStream );
64 bool Ppt97Animation::operator < ( const Ppt97Animation& rAnimation ) const
66 return m_aAtom.nOrderID < rAnimation.m_aAtom.nOrderID;
68 bool Ppt97Animation::operator > ( const Ppt97Animation& rAnimation ) const
70 return m_aAtom.nOrderID > rAnimation.m_aAtom.nOrderID;
72 bool Ppt97Animation::HasEffect() const
74 return m_aAtom.nBuildType != 0;
76 bool Ppt97Animation::HasParagraphEffect() const
78 return m_aAtom.nBuildType > 1;
80 sal_Int32 Ppt97Animation::GetParagraphLevel() const
82 sal_Int32 nParagraphLevel = 0;
83 if(m_aAtom.nBuildType>1)
84 nParagraphLevel = m_aAtom.nBuildType-1;
85 return nParagraphLevel;
87 bool Ppt97Animation::HasSoundEffect() const
89 return m_aAtom.nSoundRef && m_aAtom.nFlags & 0x0010;
91 bool Ppt97Animation::HasStopPreviousSound() const
93 return m_aAtom.nFlags & 0x0040;
95 bool Ppt97Animation::HasReverseOrder() const
97 return m_aAtom.nFlags & 0x001;
99 bool Ppt97Animation::HasAnimateAssociatedShape() const
101 return m_aAtom.nFlags & 0x004000;
103 bool Ppt97Animation::HasAfterEffect() const
105 return m_aAtom.nAfterEffect != 0;
107 bool Ppt97Animation::HasAfterEffect_ChangeColor() const
109 return m_aAtom.nAfterEffect == 1;
111 bool Ppt97Animation::HasAfterEffect_DimAtNextEffect() const
113 return m_aAtom.nAfterEffect == 2;
115 #ifdef FUTURE
116 bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
118 return m_aAtom.nAfterEffect == 3;
120 #endif
121 void Ppt97Animation::SetSoundFileUrl( const OUString& rSoundFileUrl )
123 m_aSoundFileUrl = rSoundFileUrl;
126 double Ppt97Animation::GetDelayTimeInSeconds() const
128 return m_aAtom.nDelayTime != 0X7FFFFFFF ? m_aAtom.nDelayTime/1000.0 : 0.0;
131 bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds ) const
133 UpdateCacheData();
134 if( m_bHasSpecialDuration )
135 rfDurationInSeconds = m_fDurationInSeconds;
136 return m_bHasSpecialDuration;
139 bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const
141 bool bRet = false;
142 switch(GetTextAnimationType())
144 case presentation::TextAnimationType::BY_LETTER:
145 rfTextIterationDelay = 0.075;
146 bRet = true;
147 break;
148 case presentation::TextAnimationType::BY_WORD:
149 rfTextIterationDelay = 0.3;
150 bRet = true;
151 break;
152 default:
153 break;
155 return bRet;
158 void Ppt97Animation::SetDimColor( Color nDimColor )
160 m_aAtom.nDimColor = nDimColor;
162 void Ppt97Animation::SetAnimateAssociatedShape( bool bAnimate )
164 if( !bAnimate )
166 //the appear effect cannot be animated without text
167 if( GetPresetId() == "ooo-entrance-appear" )
168 return;
169 //the random effect may be the appear effect and then has the same problem
170 if( GetPresetId() == "ooo-entrance-random" )
172 //this case is not 100% correct -> feel free to complete
173 //i consider this case as seldom and not that problematic and a simple correct fix is not in sight
174 SAL_INFO("sd", "you tried to deselect the animation of the form for random animation-> this has been refused");
175 return;
180 if(bAnimate)
181 m_aAtom.nFlags = m_aAtom.nFlags | 0x004000;
182 else if( HasAnimateAssociatedShape() )
184 m_aAtom.nFlags = m_aAtom.nFlags ^ 0x004000;
188 sal_Int16 Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
190 sal_Int16 nRet = presentation::EffectNodeType::ON_CLICK;
191 if( m_aAtom.nFlags & 0x04 )
193 nRet = presentation::EffectNodeType::AFTER_PREVIOUS;
195 return nRet;
198 sal_Int16 Ppt97Animation::GetTextAnimationType() const
200 sal_Int16 nRet = presentation::TextAnimationType::BY_PARAGRAPH;
201 switch( m_aAtom.nSubEffect )
203 case 0:
204 break;
205 case 2:
206 nRet = presentation::TextAnimationType::BY_LETTER;
207 break;
208 default:
209 nRet = presentation::TextAnimationType::BY_WORD;
210 break;
212 return nRet;
214 OUString const & Ppt97Animation::GetPresetId() const
216 UpdateCacheData();
217 return m_aPresetId;
219 OUString const & Ppt97Animation::GetPresetSubType() const
221 UpdateCacheData();
222 return m_aSubType;
225 void Ppt97Animation::ClearCacheData() const
227 m_aPresetId.clear();
228 m_aSubType.clear();
229 m_bHasSpecialDuration = false;
230 m_fDurationInSeconds = 0.001;
232 void Ppt97Animation::UpdateCacheData() const
234 if( !m_bDirtyCache )
235 return;
237 ClearCacheData();
239 if( !HasEffect() )
241 m_bDirtyCache = false;
242 return;
245 switch( m_aAtom.nFlyMethod )
247 case 0x0:
248 m_aPresetId = "ooo-entrance-appear"; // --- appear ---
249 break;
250 case 0x01:
251 m_aPresetId = "ooo-entrance-random"; // --- random ---
252 break;
253 case 0x02: // --- blinds effect ---
255 switch ( m_aAtom.nFlyDirection )
257 case 0x0:
258 m_aPresetId = "ooo-entrance-venetian-blinds";
259 m_aSubType = "horizontal"; // horizontal
260 break;
261 case 0x1:
262 m_aPresetId = "ooo-entrance-venetian-blinds";
263 m_aSubType = "vertical"; // vertical
264 break;
267 break;
268 case 0x03: // --- (hor/ver) shifted appear ---
270 switch ( m_aAtom.nFlyDirection )
272 case 0x0:
273 m_aPresetId = "ooo-entrance-checkerboard";
274 m_aSubType = "across"; // vertical ???
275 break;
276 case 0x1:
277 m_aPresetId = "ooo-entrance-checkerboard";
278 m_aSubType = "downward"; // horizontal ???
279 break;
282 break;
283 case 0x05:
284 m_aPresetId = "ooo-entrance-dissolve-in";
285 break;
286 case 0x08: // --- (hor/ver) lines ---
288 switch ( m_aAtom.nFlyDirection )
290 case 0x0:
291 m_aPresetId = "ooo-entrance-random-bars";
292 m_aSubType = "vertical"; // horizontal ???
293 break;
294 case 0x1:
295 m_aPresetId = "ooo-entrance-random-bars";
296 m_aSubType = "horizontal"; // vertical ???
297 break;
300 break;
301 case 0x09: // --- diagonal ---
303 switch ( m_aAtom.nFlyDirection )
305 case 0x4:
306 m_aPresetId = "ooo-entrance-diagonal-squares";
307 m_aSubType = "left-to-top"; // to left top
308 break;
309 case 0x5:
310 m_aPresetId = "ooo-entrance-diagonal-squares";
311 m_aSubType = "right-to-top"; // to right top
312 break;
313 case 0x6:
314 m_aPresetId = "ooo-entrance-diagonal-squares";
315 m_aSubType = "left-to-bottom"; // to left bottom
316 break;
317 case 0x7:
318 m_aPresetId = "ooo-entrance-diagonal-squares";
319 m_aSubType = "right-to-bottom"; // to right bottom
320 break;
323 break;
324 case 0x0a: // --- roll/wipe ---
326 switch ( m_aAtom.nFlyDirection )
328 case 0x0:
329 m_aPresetId = "ooo-entrance-wipe";
330 m_aSubType = "from-right"; // from right
331 break;
332 case 0x1:
333 m_aPresetId = "ooo-entrance-wipe";
334 m_aSubType = "from-bottom"; // from bottom
335 break;
336 case 0x2:
337 m_aPresetId = "ooo-entrance-wipe";
338 m_aSubType = "from-left"; // from left
339 break;
340 case 0x3:
341 m_aPresetId = "ooo-entrance-wipe";
342 m_aSubType = "from-top"; // from top
343 break;
346 break;
347 case 0x0b: //--- fade in ---
349 switch ( m_aAtom.nFlyDirection )
351 case 0x0:
352 m_aPresetId = "ooo-entrance-box";
353 m_aSubType = "out"; // from center
354 break;
355 case 0x1:
356 m_aPresetId = "ooo-entrance-box";
357 m_aSubType = "in"; // to center
358 break;
361 break;
362 case 0x0c: // --- text effects ---
364 switch ( m_aAtom.nFlyDirection )
366 case 0x0:
367 m_aPresetId = "ooo-entrance-fly-in";
368 m_aSubType = "from-left";
370 break;
371 case 0x1:
372 m_aPresetId = "ooo-entrance-fly-in";
373 m_aSubType = "from-top";
374 break;
375 case 0x2:
376 m_aPresetId = "ooo-entrance-fly-in";
377 m_aSubType = "from-right";
378 break;
379 case 0x3:
380 m_aPresetId = "ooo-entrance-fly-in";
381 m_aSubType = "from-bottom";
382 break;
383 case 0x4:
384 m_aPresetId = "ooo-entrance-fly-in";
385 m_aSubType = "from-top-left";
386 break;
387 case 0x5:
388 m_aPresetId = "ooo-entrance-fly-in";
389 m_aSubType = "from-top-right";
390 break;
391 case 0x6:
392 m_aPresetId = "ooo-entrance-fly-in";
393 m_aSubType = "from-bottom-left";
394 break;
395 case 0x7:
396 m_aPresetId = "ooo-entrance-fly-in";
397 m_aSubType = "from-bottom-right";
398 break;
399 case 0x8: // -- short text effects --
400 m_aPresetId = "ooo-entrance-peek-in";
401 m_aSubType = "from-left";
402 break;
403 case 0x9:
404 m_aPresetId = "ooo-entrance-peek-in";
405 m_aSubType = "from-bottom";
406 break;
407 case 0xa:
408 m_aPresetId = "ooo-entrance-peek-in";
409 m_aSubType = "from-right";
410 break;
411 case 0xb:
412 m_aPresetId = "ooo-entrance-peek-in";
413 m_aSubType = "from-top";
414 break;
415 case 0xc: // -- slow text effects --
417 m_aPresetId = "ooo-entrance-fly-in-slow";
418 m_aSubType = "from-left";
420 break;
421 case 0xd:
423 m_aPresetId = "ooo-entrance-fly-in-slow";
424 m_aSubType = "from-top";
426 break;
427 case 0xe:
429 m_aPresetId = "ooo-entrance-fly-in-slow";
430 m_aSubType = "from-right";
432 break;
433 case 0xf:
435 m_aPresetId = "ooo-entrance-fly-in-slow";
436 m_aSubType = "from-bottom";
438 break;
439 case 0x10: // --- zoom ---
440 m_aPresetId = "ooo-entrance-zoom";
441 m_aSubType = "in";
442 break;
443 case 0x11:
444 m_aPresetId = "ooo-entrance-zoom";
445 m_aSubType = "in-slightly";
446 break;
447 case 0x12:
448 m_aPresetId = "ooo-entrance-zoom";
449 m_aSubType = "out";
450 break;
451 case 0x13:
452 m_aPresetId = "ooo-entrance-zoom";
453 m_aSubType = "out-slightly";
454 break;
455 case 0x14:
456 m_aPresetId = "ooo-entrance-zoom";
457 m_aSubType = "in-from-screen-center";
458 break;
459 case 0x15:
460 m_aPresetId = "ooo-entrance-zoom";
461 m_aSubType = "out-from-screen-center";
462 break;
463 case 0x16: // --- stretch ---
464 m_aPresetId = "ooo-entrance-stretchy";
465 m_aSubType = "across";
466 break;
467 case 0x17:
468 m_aPresetId = "ooo-entrance-stretchy";
469 m_aSubType = "from-left";
470 break;
471 case 0x18:
472 m_aPresetId = "ooo-entrance-stretchy";
473 m_aSubType = "from-top";
474 break;
475 case 0x19:
476 m_aPresetId = "ooo-entrance-stretchy";
477 m_aSubType = "from-right";
478 break;
479 case 0x1a:
480 m_aPresetId = "ooo-entrance-stretchy";
481 m_aSubType = "from-bottom";
482 break;
483 case 0x1b: // --- rotate ---
484 m_aPresetId = "ooo-entrance-swivel";
485 m_aSubType = "vertical";
486 break;
487 case 0x1c: // --- spirale ---
488 m_aPresetId = "ooo-entrance-spiral-in";
489 break;
492 break;
493 case 0x0d: // --- open/close ---
495 switch ( m_aAtom.nFlyDirection )
497 case 0x0:
498 m_aPresetId = "ooo-entrance-split";
499 m_aSubType = "horizontal-out"; //horizontal open
500 break;
501 case 0x1:
502 m_aPresetId = "ooo-entrance-split";
503 m_aSubType = "horizontal-in"; //horizontal close
504 break;
505 case 0x2:
506 m_aPresetId = "ooo-entrance-split";
507 m_aSubType = "vertical-out"; // vertical open
508 break;
509 case 0x3:
510 m_aPresetId = "ooo-entrance-split";
511 m_aSubType = "vertical-in"; // vertical close
512 break;
515 break;
516 case 0x0e: // --- blink ---
518 m_aPresetId = "ooo-entrance-flash-once";
519 switch ( m_aAtom.nFlyDirection )
521 case 0x0: //fast
522 m_fDurationInSeconds = 0.075;
523 m_bHasSpecialDuration = true;
524 break;
525 case 0x1: //medium
526 m_fDurationInSeconds = 0.5;
527 m_bHasSpecialDuration = true;
528 break;
529 case 0x2: //slow
530 m_fDurationInSeconds = 1.0;
531 m_bHasSpecialDuration = true;
532 break;
535 break;
536 default:
538 m_aPresetId = "ooo-entrance-appear";
539 OSL_FAIL("no effect mapped");
541 break;
543 m_bDirtyCache = false;
546 void Ppt97Animation::createAndSetCustomAnimationEffect( SdrObject* pObj )
549 if( !HasEffect() )
550 return;
551 if( !pObj || !pObj->getSdrPageFromSdrObject() )
553 OSL_FAIL("no valid SdrObject or page found for ppt import");
554 return;
557 uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject( pObj );
558 if( !xShape.is() )
560 OSL_FAIL("no XShape interface found for ppt import");
561 return;
563 ::sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
564 if( !pMainSequence )
566 OSL_FAIL("no MainSequence found for ppt import");
567 return;
570 const ::sd::CustomAnimationPresets& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
571 ::sd::CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( GetPresetId() ) );
572 if( !pPreset )
574 OSL_FAIL("no suitable preset found for ppt import");
575 return;
578 //--------------start doing something
580 //1. ------ create an effect from the presets ------
581 ::sd::CustomAnimationEffectPtr pEffect = std::make_shared<::sd::CustomAnimationEffect>( pPreset->create( GetPresetSubType() ) );
583 //2. ------ adapt the created effect ------
585 // set the shape targeted by this effect
586 pEffect->setTarget( css::uno::Any( xShape ) );
588 pEffect->setBegin( GetDelayTimeInSeconds() );
590 // some effects need a different duration than that of the mapped preset effect
591 double fDurationInSeconds = 1.0; //in seconds
592 if( GetSpecialDuration( fDurationInSeconds ) )
593 pEffect->setDuration( fDurationInSeconds );
595 // set after effect
596 if( HasAfterEffect() )
598 pEffect->setHasAfterEffect( true );
599 if( HasAfterEffect_ChangeColor() )
600 pEffect->setDimColor( uno::Any( GetDimColor() ) );
601 else
602 pEffect->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
605 // set sound effect
606 if( HasSoundEffect() )
607 pEffect->createAudio( uno::Any( m_aSoundFileUrl ) );
609 // text iteration
610 pEffect->setIterateType( GetTextAnimationType() );
612 // some effects need a different delay between text iteration than that of the mapped preset effect
613 double fTextIterationDelay = 1.0;
614 if( GetSpecialTextIterationDelay( fTextIterationDelay ) )
615 pEffect->setIterateInterval( fTextIterationDelay );
617 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
618 pEffect->setNodeType( GetEffectNodeType() );
620 //set stop sound effect
621 if( HasStopPreviousSound() )
622 pEffect->setStopAudio();
624 // append the effect to the main sequence
625 if( !HasParagraphEffect() )
627 // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
628 pEffect->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE );
631 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
632 pMainSequence->append( pEffect );
633 if( HasParagraphEffect() )
635 sal_Int32 nParagraphLevel = GetParagraphLevel();
636 double fDelaySeconds = GetDelayTimeInSeconds();
637 bool bAnimateAssociatedShape = HasAnimateAssociatedShape();//or only text
638 bool bTextReverse = HasReverseOrder();
640 // now create effects for each paragraph
641 ::sd::CustomAnimationTextGroupPtr pGroup = pMainSequence->
642 createTextGroup( pEffect, nParagraphLevel, fDelaySeconds, bAnimateAssociatedShape, bTextReverse );
644 if( pGroup )
646 const ::sd::EffectSequence& rEffects = pGroup->getEffects();
648 ::sd::CustomAnimationEffectPtr pLastEffect;
649 sal_Int32 nIndex = 0;
650 for( const auto& rxEffect : rEffects )
652 ::sd::CustomAnimationEffectPtr pGroupEffect(rxEffect);
654 ////todo? if( nIndex > 1 && pLastEffect && HasSoundEffect() )
655 //// pLastEffect->setStopAudio();
656 if( nIndex < 2 )
658 pGroupEffect->setNodeType( GetEffectNodeType() );
660 else if( nIndex > 0 )
662 bool bAtParagraphBegin = false;
663 if(!bTextReverse)
664 bAtParagraphBegin = pGroupEffect->getParaDepth() < nParagraphLevel;
665 else
666 bAtParagraphBegin = !pLastEffect || pLastEffect->getParaDepth() < nParagraphLevel;
667 if( bAtParagraphBegin )
668 pGroupEffect->setNodeType( GetEffectNodeType() );
669 else if( GetTextAnimationType() == presentation::TextAnimationType::BY_PARAGRAPH )
670 pGroupEffect->setNodeType( presentation::EffectNodeType::WITH_PREVIOUS );
671 else
672 pGroupEffect->setNodeType( presentation::EffectNodeType::AFTER_PREVIOUS );
674 pLastEffect = pGroupEffect;
675 nIndex++;
679 pMainSequence->rebuild();
682 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */