LibreOffice Module sd (master) 1
ppt97animations.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 "ppt97animations.hxx"
21
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>
29#include <com/sun/star/presentation/TextAnimationType.hpp>
30#include <com/sun/star/presentation/EffectNodeType.hpp>
31#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
32
33using namespace ::com::sun::star;
34
36{
37 sal_uInt32 nTmp;
38 rIn.ReadUInt32( nTmp );
40 rIn.ReadUInt32( nFlags );
41 rIn.ReadUInt32( nSoundRef );
42 rIn.ReadInt32( nDelayTime );
43 rIn.ReadUInt16( nOrderID );
45 rIn.ReadUChar( nBuildType );
46 rIn.ReadUChar( nFlyMethod );
49 rIn.ReadUChar( nSubEffect );
50 rIn.ReadUChar( nOLEVerb );
51 rIn.ReadUChar( nUnknown1 );
52 rIn.ReadUChar( nUnknown2 );
53}
54
56 : m_aAtom()
57 , m_bDirtyCache(true)
58 , m_bHasSpecialDuration(false)
59 , m_fDurationInSeconds(0.001)
60{
62}
63
64bool Ppt97Animation::operator < ( const Ppt97Animation& rAnimation ) const
65{
66 return m_aAtom.nOrderID < rAnimation.m_aAtom.nOrderID;
67}
68bool Ppt97Animation::operator > ( const Ppt97Animation& rAnimation ) const
69{
70 return m_aAtom.nOrderID > rAnimation.m_aAtom.nOrderID;
71}
73{
74 return m_aAtom.nBuildType != 0;
75}
77{
78 return m_aAtom.nBuildType > 1;
79}
81{
82 sal_Int32 nParagraphLevel = 0;
84 nParagraphLevel = m_aAtom.nBuildType-1;
85 return nParagraphLevel;
86}
88{
89 return m_aAtom.nSoundRef && m_aAtom.nFlags & 0x0010;
90}
92{
93 return m_aAtom.nFlags & 0x0040;
94}
96{
97 return m_aAtom.nFlags & 0x001;
98}
100{
101 return m_aAtom.nFlags & 0x004000;
102}
104{
105 return m_aAtom.nAfterEffect != 0;
106}
108{
109 return m_aAtom.nAfterEffect == 1;
110}
112{
113 return m_aAtom.nAfterEffect == 2;
114}
115#ifdef FUTURE
116bool Ppt97Animation::HasAfterEffect_DimAfterEffect() const
117{
118 return m_aAtom.nAfterEffect == 3;
119}
120#endif
121void Ppt97Animation::SetSoundFileUrl( const OUString& rSoundFileUrl )
122{
123 m_aSoundFileUrl = rSoundFileUrl;
124}
125
127{
128 return m_aAtom.nDelayTime != 0X7FFFFFFF ? m_aAtom.nDelayTime/1000.0 : 0.0;
129}
130
131bool Ppt97Animation::GetSpecialDuration( double& rfDurationInSeconds ) const
132{
135 rfDurationInSeconds = m_fDurationInSeconds;
137}
138
139bool Ppt97Animation::GetSpecialTextIterationDelay( double& rfTextIterationDelay ) const
140{
141 bool bRet = false;
142 switch(GetTextAnimationType())
143 {
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;
154 }
155 return bRet;
156}
157
159{
160 m_aAtom.nDimColor = nDimColor;
161}
163{
164 if( !bAnimate )
165 {
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" )
171 {
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;
176 }
177
178 }
179
180 if(bAnimate)
181 m_aAtom.nFlags = m_aAtom.nFlags | 0x004000;
182 else if( HasAnimateAssociatedShape() )
183 {
184 m_aAtom.nFlags = m_aAtom.nFlags ^ 0x004000;
185 }
186}
187
188sal_Int16 Ppt97Animation::GetEffectNodeType() const //see css::presentation::EffectNodeType
189{
190 sal_Int16 nRet = presentation::EffectNodeType::ON_CLICK;
191 if( m_aAtom.nFlags & 0x04 )
192 {
193 nRet = presentation::EffectNodeType::AFTER_PREVIOUS;
194 }
195 return nRet;
196}
197
199{
200 sal_Int16 nRet = presentation::TextAnimationType::BY_PARAGRAPH;
201 switch( m_aAtom.nSubEffect )
202 {
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;
211 }
212 return nRet;
213}
214OUString const & Ppt97Animation::GetPresetId() const
215{
217 return m_aPresetId;
218}
219OUString const & Ppt97Animation::GetPresetSubType() const
220{
222 return m_aSubType;
223}
224
226{
227 m_aPresetId.clear();
228 m_aSubType.clear();
229 m_bHasSpecialDuration = false;
230 m_fDurationInSeconds = 0.001;
231}
233{
234 if( !m_bDirtyCache )
235 return;
236
238
239 if( !HasEffect() )
240 {
241 m_bDirtyCache = false;
242 return;
243 }
244
245 switch( m_aAtom.nFlyMethod )
246 {
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 ---
254 {
255 switch ( m_aAtom.nFlyDirection )
256 {
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;
265 }
266 }
267 break;
268 case 0x03: // --- (hor/ver) shifted appear ---
269 {
270 switch ( m_aAtom.nFlyDirection )
271 {
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;
280 }
281 }
282 break;
283 case 0x05:
284 m_aPresetId = "ooo-entrance-dissolve-in";
285 break;
286 case 0x08: // --- (hor/ver) lines ---
287 {
288 switch ( m_aAtom.nFlyDirection )
289 {
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;
298 }
299 }
300 break;
301 case 0x09: // --- diagonal ---
302 {
303 switch ( m_aAtom.nFlyDirection )
304 {
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;
321 }
322 }
323 break;
324 case 0x0a: // --- roll/wipe ---
325 {
326 switch ( m_aAtom.nFlyDirection )
327 {
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;
344 }
345 }
346 break;
347 case 0x0b: //--- fade in ---
348 {
349 switch ( m_aAtom.nFlyDirection )
350 {
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;
359 }
360 }
361 break;
362 case 0x0c: // --- text effects ---
363 {
364 switch ( m_aAtom.nFlyDirection )
365 {
366 case 0x0:
367 m_aPresetId = "ooo-entrance-fly-in";
368 m_aSubType = "from-left";
369
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 --
416 {
417 m_aPresetId = "ooo-entrance-fly-in-slow";
418 m_aSubType = "from-left";
419 }
420 break;
421 case 0xd:
422 {
423 m_aPresetId = "ooo-entrance-fly-in-slow";
424 m_aSubType = "from-top";
425 }
426 break;
427 case 0xe:
428 {
429 m_aPresetId = "ooo-entrance-fly-in-slow";
430 m_aSubType = "from-right";
431 }
432 break;
433 case 0xf:
434 {
435 m_aPresetId = "ooo-entrance-fly-in-slow";
436 m_aSubType = "from-bottom";
437 }
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;
490 }
491 }
492 break;
493 case 0x0d: // --- open/close ---
494 {
495 switch ( m_aAtom.nFlyDirection )
496 {
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;
513 }
514 }
515 break;
516 case 0x0e: // --- blink ---
517 {
518 m_aPresetId = "ooo-entrance-flash-once";
519 switch ( m_aAtom.nFlyDirection )
520 {
521 case 0x0: //fast
522 m_fDurationInSeconds = 0.075;
524 break;
525 case 0x1: //medium
528 break;
529 case 0x2: //slow
532 break;
533 }
534 }
535 break;
536 default:
537 {
538 m_aPresetId = "ooo-entrance-appear";
539 OSL_FAIL("no effect mapped");
540 }
541 break;
542 }
543 m_bDirtyCache = false;
544}
545
547{
548
549 if( !HasEffect() )
550 return;
551 if( !pObj || !pObj->getSdrPageFromSdrObject() )
552 {
553 OSL_FAIL("no valid SdrObject or page found for ppt import");
554 return;
555 }
556
557 uno::Reference< drawing::XShape > xShape = GetXShapeForSdrObject( pObj );
558 if( !xShape.is() )
559 {
560 OSL_FAIL("no XShape interface found for ppt import");
561 return;
562 }
563 ::sd::MainSequencePtr pMainSequence = static_cast<SdPage*>(pObj->getSdrPageFromSdrObject())->getMainSequence();
564 if( !pMainSequence )
565 {
566 OSL_FAIL("no MainSequence found for ppt import");
567 return;
568 }
569
570 const ::sd::CustomAnimationPresets& rPresets( ::sd::CustomAnimationPresets::getCustomAnimationPresets() );
571 ::sd::CustomAnimationPresetPtr pPreset( rPresets.getEffectDescriptor( GetPresetId() ) );
572 if( !pPreset )
573 {
574 OSL_FAIL("no suitable preset found for ppt import");
575 return;
576 }
577
578 //--------------start doing something
579
580 //1. ------ create an effect from the presets ------
581 ::sd::CustomAnimationEffectPtr pEffect = std::make_shared<::sd::CustomAnimationEffect>( pPreset->create( GetPresetSubType() ) );
582
583 //2. ------ adapt the created effect ------
584
585 // set the shape targeted by this effect
586 pEffect->setTarget( css::uno::Any( xShape ) );
587
588 pEffect->setBegin( GetDelayTimeInSeconds() );
589
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 );
594
595 // set after effect
596 if( HasAfterEffect() )
597 {
598 pEffect->setHasAfterEffect( true );
600 pEffect->setDimColor( uno::Any( GetDimColor() ) );
601 else
602 pEffect->setAfterEffectOnNext( HasAfterEffect_DimAtNextEffect() );
603 }
604
605 // set sound effect
606 if( HasSoundEffect() )
607 pEffect->createAudio( uno::Any( m_aSoundFileUrl ) );
608
609 // text iteration
610 pEffect->setIterateType( GetTextAnimationType() );
611
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 );
616
617 // is the effect started on click or after the last effect (Another possible value is EffectNodeType::WITH_PREVIOUS )
618 pEffect->setNodeType( GetEffectNodeType() );
619
620 //set stop sound effect
622 pEffect->setStopAudio();
623
624 // append the effect to the main sequence
625 if( !HasParagraphEffect() )
626 {
627 // TODO: !HasAnimateAssociatedShape() can possibly have this set to ONLY_TEXT - see i#42737
628 pEffect->setTargetSubItem( presentation::ShapeAnimationSubType::AS_WHOLE );
629 }
630
631 //3. ------ put the created effect to the model and do some last changes fro paragraph effects ------
632 pMainSequence->append( pEffect );
633 if( HasParagraphEffect() )
634 {
635 sal_Int32 nParagraphLevel = GetParagraphLevel();
636 double fDelaySeconds = GetDelayTimeInSeconds();
637 bool bAnimateAssociatedShape = HasAnimateAssociatedShape();//or only text
638 bool bTextReverse = HasReverseOrder();
639
640 // now create effects for each paragraph
641 ::sd::CustomAnimationTextGroupPtr pGroup = pMainSequence->
642 createTextGroup( pEffect, nParagraphLevel, fDelaySeconds, bAnimateAssociatedShape, bTextReverse );
643
644 if( pGroup )
645 {
646 const ::sd::EffectSequence& rEffects = pGroup->getEffects();
647
649 sal_Int32 nIndex = 0;
650 for( const auto& rxEffect : rEffects )
651 {
652 ::sd::CustomAnimationEffectPtr pGroupEffect(rxEffect);
653
656 if( nIndex < 2 )
657 {
658 pGroupEffect->setNodeType( GetEffectNodeType() );
659 }
660 else if( nIndex > 0 )
661 {
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 );
673 }
674 pLastEffect = pGroupEffect;
675 nIndex++;
676 }
677 }
678 }
679 pMainSequence->rebuild();
680}
681
682/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt32 nFlags
0x0004: time instead of click
sal_uInt8 nAfterEffect
nAfterEffect: 0: none; 1: change color; 2: dim on next effect; 3: dim after effect;
sal_Int32 nDelayTime
1/1000 sec
void ReadStream(SvStream &rIn)
this is a helping class for import of PPT 97 animations
bool HasAfterEffect_DimAtNextEffect() const
bool HasAnimateAssociatedShape() const
double GetDelayTimeInSeconds() const
void SetDimColor(Color nDimColor)
void UpdateCacheData() const
bool HasParagraphEffect() const
bool operator<(const Ppt97Animation &rAnimation) const
OUString m_aSoundFileUrl
this needs to be set in addition from outside as this class has not the knowledge to translate the so...
OUString const & GetPresetId() const
bool GetSpecialDuration(double &rfDurationInSeconds) const
void createAndSetCustomAnimationEffect(SdrObject *pObj)
this method creates a CustomAnimationEffect for the given SdrObject from internal data and stores the...
Ppt97Animation(SvStream &rIn)
void SetAnimateAssociatedShape(bool bAnimate)
sal_Int16 GetTextAnimationType() const
bool HasAfterEffect_ChangeColor() const
sal_Int32 GetParagraphLevel() const
paragraph level that is animated ( that paragraph and higher levels )
sal_Int32 GetDimColor() const
bool HasReverseOrder() const
bool operator>(const Ppt97Animation &rAnimation) const
bool HasStopPreviousSound() const
bool HasSoundEffect() const
OUString const & GetPresetSubType() const
void SetSoundFileUrl(const OUString &rSoundFileUrl)
sal_Int16 GetEffectNodeType() const
void ClearCacheData() const
bool HasEffect() const
bool HasAfterEffect() const
bool GetSpecialTextIterationDelay(double &rfTextIterationDelay) const
Ppt97AnimationInfoAtom m_aAtom
pure input from stream
SdrPage * getSdrPageFromSdrObject() const
SvStream & ReadUInt32(sal_uInt32 &rUInt32)
SvStream & ReadInt32(sal_Int32 &rInt32)
SvStream & ReadUInt16(sal_uInt16 &rUInt16)
SvStream & ReadUChar(unsigned char &rChar)
static const CustomAnimationPresets & getCustomAnimationPresets()
This method gets presets instance, which is localized for the current user's locale.
ColorTransparency
Reference< XInputStream > rInputStream
sal_Int32 nIndex
#define SAL_INFO(area, stream)
std::list< CustomAnimationEffectPtr > EffectSequence
std::shared_ptr< MainSequence > MainSequencePtr
std::shared_ptr< CustomAnimationTextGroup > CustomAnimationTextGroupPtr
std::shared_ptr< CustomAnimationPreset > CustomAnimationPresetPtr
std::shared_ptr< CustomAnimationEffect > CustomAnimationEffectPtr
SVXCORE_DLLPUBLIC css::uno::Reference< css::drawing::XShape > GetXShapeForSdrObject(SdrObject *pObj) noexcept