Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/oox/source/ppt/timenodelistcontext.cxx
Line
Count
Source
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 <oox/ppt/timenodelistcontext.hxx>
21
22
#include <rtl/math.hxx>
23
#include <sal/log.hxx>
24
#include <comphelper/diagnose_ex.hxx>
25
26
#include <com/sun/star/animations/AnimationTransformType.hpp>
27
#include <com/sun/star/animations/AnimationCalcMode.hpp>
28
#include <com/sun/star/animations/AnimationColorSpace.hpp>
29
#include <com/sun/star/animations/AnimationNodeType.hpp>
30
#include <com/sun/star/animations/ValuePair.hpp>
31
#include <com/sun/star/presentation/EffectCommands.hpp>
32
#include <com/sun/star/beans/NamedValue.hpp>
33
34
#include <oox/helper/attributelist.hxx>
35
#include <oox/core/xmlfilterbase.hxx>
36
#include <oox/drawingml/drawingmltypes.hxx>
37
#include <drawingml/colorchoicecontext.hxx>
38
#include <oox/ppt/slidetransition.hxx>
39
#include <oox/token/namespaces.hxx>
40
#include <oox/token/tokens.hxx>
41
#include <o3tl/string_view.hxx>
42
#include <sax/fastattribs.hxx>
43
#include <utility>
44
45
#include "animvariantcontext.hxx"
46
#include "commonbehaviorcontext.hxx"
47
#include "conditioncontext.hxx"
48
#include "commontimenodecontext.hxx"
49
#include "timeanimvaluecontext.hxx"
50
#include "animationtypes.hxx"
51
#include "timetargetelementcontext.hxx"
52
53
using namespace ::oox::core;
54
using namespace ::oox::drawingml;
55
using namespace ::com::sun::star;
56
using namespace ::com::sun::star::uno;
57
using namespace ::com::sun::star::animations;
58
using namespace ::com::sun::star::presentation;
59
using namespace ::com::sun::star::xml::sax;
60
using ::com::sun::star::beans::NamedValue;
61
62
namespace {
63
64
    oox::ppt::AnimationAttributeEnum getAttributeEnumByAPIName(std::u16string_view rAPIName)
65
237
    {
66
237
        oox::ppt::AnimationAttributeEnum eResult = oox::ppt::AnimationAttributeEnum::UNKNOWN;
67
237
        const oox::ppt::ImplAttributeNameConversion *attrConv = oox::ppt::getAttributeConversionList();
68
1.50k
        while(attrConv->mpAPIName != nullptr)
69
1.50k
        {
70
1.50k
            if(o3tl::equalsAscii(rAPIName, attrConv->mpAPIName))
71
237
            {
72
237
                eResult = attrConv->meAttribute;
73
237
                break;
74
237
            }
75
1.26k
            attrConv++;
76
1.26k
        }
77
237
        return eResult;
78
237
    }
79
80
    bool convertAnimationValueWithTimeNode(const oox::ppt::TimeNodePtr& pNode, css::uno::Any &rAny)
81
237
    {
82
237
        css::uno::Any aAny = pNode->getNodeProperties()[oox::ppt::NP_ATTRIBUTENAME];
83
237
        OUString aNameList;
84
237
        aAny >>= aNameList;
85
86
        // only get first token.
87
237
        return oox::ppt::convertAnimationValue(getAttributeEnumByAPIName(o3tl::getToken(aNameList, 0, ';')), rAny);
88
237
    }
89
90
    css::uno::Any convertPointPercent(const css::awt::Point& rPoint)
91
108
    {
92
108
        css::animations::ValuePair aPair;
93
        // rPoint.X and rPoint.Y are in 1000th of a percent, but we only need ratio.
94
108
        aPair.First <<= static_cast<double>(rPoint.X) / 100000.0;
95
108
        aPair.Second <<= static_cast<double>(rPoint.Y) / 100000.0;
96
108
        return Any(aPair);
97
108
    }
98
}
99
100
namespace oox::ppt {
101
102
    namespace {
103
104
    struct AnimColor
105
    {
106
        AnimColor(sal_Int16 cs, sal_Int32 o, sal_Int32 t, sal_Int32 th )
107
12
            : colorSpace( cs ), one( o ), two( t ), three( th )
108
12
            {
109
12
            }
110
111
        Any get() const
112
0
            {
113
0
                sal_Int32 nColor;
114
0
                Any aColor;
115
116
0
                switch( colorSpace )
117
0
                {
118
0
                case AnimationColorSpace::HSL:
119
0
                    aColor <<= Sequence< double >{ one / 100000.0, two / 100000.0, three / 100000.0 };
120
0
                    break;
121
0
                case AnimationColorSpace::RGB:
122
0
                    nColor = ( ( ( one * 128 ) / 1000 ) & 0xff ) << 16
123
0
                        | ( ( ( two * 128 ) / 1000 ) & 0xff ) << 8
124
0
                        | ( ( ( three * 128 ) / 1000 )  & 0xff );
125
0
                    aColor <<= nColor;
126
0
                    break;
127
0
                default:
128
0
                    nColor = 0;
129
0
                    aColor <<= nColor;
130
0
                    break;
131
0
                }
132
0
                return  aColor;
133
0
            }
134
135
        sal_Int16 colorSpace;
136
        sal_Int32 one;
137
        sal_Int32 two;
138
        sal_Int32 three;
139
    };
140
141
    /** CT_TLMediaNodeAudio
142
            CT_TLMediaNodeVideo */
143
    class MediaNodeContext
144
        : public TimeNodeContext
145
    {
146
    public:
147
        MediaNodeContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
148
                            const Reference< XFastAttributeList >& xAttribs,
149
                            const TimeNodePtr & pNode )
150
0
            : TimeNodeContext( rParent, aElement, pNode )
151
0
                , mbIsNarration( false )
152
0
                , mbFullScrn( false )
153
0
                , mbHideDuringShow(false)
154
0
            {
155
0
                AttributeList attribs( xAttribs );
156
157
0
                switch( aElement )
158
0
                {
159
0
                case PPT_TOKEN( audio ):
160
0
                    mbIsNarration = attribs.getBool( XML_isNarration, false );
161
0
                    break;
162
0
                case PPT_TOKEN( video ):
163
0
                    mbFullScrn = attribs.getBool( XML_fullScrn, false );
164
0
                    break;
165
0
                default:
166
0
                    break;
167
0
                }
168
0
            }
169
170
        virtual void onEndElement() override
171
0
            {
172
0
                sal_Int32 aElement = getCurrentElement();
173
0
                if( aElement == PPT_TOKEN( audio ) )
174
0
                {
175
0
                    mpNode->getNodeProperties()[NP_ISNARRATION] <<= mbIsNarration;
176
0
                }
177
0
                else if( aElement == PPT_TOKEN( video ) )
178
0
                {
179
                    // TODO deal with mbFullScrn
180
0
                }
181
0
                else if (aElement == PPT_TOKEN(cMediaNode))
182
0
                {
183
0
                    mpNode->getNodeProperties()[NP_HIDEDURINGSHOW] <<= mbHideDuringShow;
184
0
                }
185
0
            }
186
187
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs) override
188
0
            {
189
0
                switch ( aElementToken )
190
0
                {
191
0
                case PPT_TOKEN( cTn ):
192
0
                    return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
193
0
                case PPT_TOKEN( tgtEl ):
194
0
                    return new TimeTargetElementContext( *this, mpNode->getTarget() );
195
0
                case PPT_TOKEN(cMediaNode):
196
0
                    mbHideDuringShow = !rAttribs.getBool(XML_showWhenStopped, true);
197
0
                    break;
198
0
                default:
199
0
                    break;
200
0
                }
201
202
0
                return this;
203
0
            }
204
205
    private:
206
        bool mbIsNarration;
207
        bool mbFullScrn;
208
        bool mbHideDuringShow;
209
    };
210
211
    /** CT_TLSetBehavior
212
     */
213
    class SetTimeNodeContext
214
        : public TimeNodeContext
215
    {
216
    public:
217
        SetTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
218
                            const TimeNodePtr & pNode )
219
109
            : TimeNodeContext( rParent, aElement, pNode )
220
109
            {
221
222
109
            }
223
224
        virtual ~SetTimeNodeContext() noexcept override
225
109
            {
226
109
                if(maTo.hasValue())
227
109
                {
228
109
                    convertAnimationValueWithTimeNode(mpNode, maTo);
229
109
                    mpNode->setTo(maTo);
230
109
                }
231
232
109
            }
233
234
            virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
235
218
            {
236
218
                switch ( aElementToken )
237
218
                {
238
109
                case PPT_TOKEN( cBhvr ):
239
109
                    return new CommonBehaviorContext ( *this, mpNode );
240
109
                case PPT_TOKEN( to ):
241
                    // CT_TLAnimVariant
242
109
                    return new AnimVariantContext( *this, aElementToken, maTo );
243
0
                default:
244
0
                    break;
245
218
                }
246
247
0
                return this;
248
218
            }
249
    private:
250
        Any  maTo;
251
    };
252
253
    /** CT_TLCommandBehavior
254
     */
255
    class CmdTimeNodeContext
256
        : public TimeNodeContext
257
    {
258
    public:
259
        CmdTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
260
                            const Reference< XFastAttributeList >& xAttribs,
261
                            const TimeNodePtr & pNode )
262
0
            : TimeNodeContext( rParent, aElement, pNode )
263
0
                , maType(0)
264
0
            {
265
0
                switch ( aElement )
266
0
                {
267
0
                case PPT_TOKEN( cmd ):
268
0
                    msCommand = xAttribs->getOptionalValue( XML_cmd );
269
0
                    maType = xAttribs->getOptionalValueToken( XML_type, 0 );
270
0
                    break;
271
0
                default:
272
0
                    break;
273
0
                }
274
0
            }
275
276
        virtual void onEndElement() override
277
0
            {
278
0
                if( !isCurrentElement( PPT_TOKEN( cmd ) ) )
279
0
                    return;
280
281
0
                try {
282
                    // see sd/source/filter/ppt/pptinanimations.cxx
283
                    // in AnimationImporter::importCommandContainer()
284
                    // REFACTOR?
285
                    // a good chunk of this code has been copied verbatim *sigh*
286
0
                    sal_Int16 nCommand = EffectCommands::CUSTOM;
287
0
                    NamedValue aParamValue;
288
289
0
                    switch( maType )
290
0
                    {
291
0
                    case XML_verb:
292
0
                        aParamValue.Name = "Verb";
293
                        // TODO make sure msCommand has what we want
294
0
                        aParamValue.Value <<= msCommand.toInt32();
295
0
                        nCommand = EffectCommands::VERB;
296
0
                        break;
297
0
                    case XML_evt:
298
0
                    case XML_call:
299
0
                        if ( msCommand == "onstopaudio" )
300
0
                        {
301
0
                            nCommand = EffectCommands::STOPAUDIO;
302
0
                        }
303
0
                        else if ( msCommand == "play" )
304
0
                        {
305
0
                            nCommand = EffectCommands::PLAY;
306
0
                        }
307
0
                        else if (msCommand.startsWith("playFrom"))
308
0
                        {
309
0
                            std::u16string_view aMediaTime( msCommand.subView( 9, msCommand.getLength() - 10 ) );
310
0
                            rtl_math_ConversionStatus eStatus;
311
0
                            double fMediaTime = ::rtl::math::stringToDouble( aMediaTime, u'.', u',', &eStatus );
312
0
                            if( eStatus == rtl_math_ConversionStatus_Ok )
313
0
                            {
314
0
                                aParamValue.Name = "MediaTime";
315
0
                                aParamValue.Value <<= fMediaTime;
316
0
                            }
317
0
                            nCommand = EffectCommands::PLAY;
318
0
                        }
319
0
                        else if ( msCommand == "togglePause" )
320
0
                        {
321
0
                            nCommand = EffectCommands::TOGGLEPAUSE;
322
0
                        }
323
0
                        else if ( msCommand == "stop" )
324
0
                        {
325
0
                            nCommand = EffectCommands::STOP;
326
0
                        }
327
0
                        break;
328
0
                    }
329
0
                    mpNode->getNodeProperties()[ NP_COMMAND ] <<= nCommand;
330
0
                    if( nCommand == EffectCommands::CUSTOM )
331
0
                    {
332
0
                        SAL_WARN("oox.ppt", "OOX: CmdTimeNodeContext::endFastElement(), unknown command!");
333
0
                        aParamValue.Name = "UserDefined";
334
0
                        aParamValue.Value <<= msCommand;
335
0
                    }
336
0
                    if( aParamValue.Value.hasValue() )
337
0
                    {
338
0
                        Sequence< NamedValue > aParamSeq( &aParamValue, 1 );
339
0
                        mpNode->getNodeProperties()[ NP_PARAMETER ] <<= aParamSeq;
340
0
                    }
341
0
                }
342
0
                catch( RuntimeException& )
343
0
                {
344
0
                    TOOLS_WARN_EXCEPTION("oox.ppt", "OOX: Exception in CmdTimeNodeContext::endFastElement()" );
345
0
                }
346
0
            }
347
348
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
349
0
            {
350
0
                switch ( aElementToken )
351
0
                {
352
0
                case PPT_TOKEN( cBhvr ):
353
0
                    return new CommonBehaviorContext ( *this, mpNode );
354
0
                default:
355
0
                    break;
356
0
                }
357
358
0
                return this;
359
0
            }
360
361
    private:
362
        OUString msCommand;
363
        sal_Int32 maType;
364
    };
365
366
    /** CT_TLTimeNodeSequence
367
     */
368
    class SequenceTimeNodeContext
369
        : public TimeNodeContext
370
    {
371
    public:
372
        SequenceTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
373
                                 const Reference< XFastAttributeList >& xAttribs,
374
                                 const TimeNodePtr & pNode )
375
700
            : TimeNodeContext( rParent, aElement, pNode )
376
700
                , mnNextAc(0)
377
700
                , mnPrevAc(0)
378
700
            {
379
700
                AttributeList attribs(xAttribs);
380
700
                mbConcurrent = attribs.getBool( XML_concurrent, false );
381
700
                mnNextAc = xAttribs->getOptionalValueToken( XML_nextAc, 0 );
382
700
                mnPrevAc = xAttribs->getOptionalValueToken( XML_prevAc, 0 );
383
700
            }
384
385
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
386
2.10k
            {
387
2.10k
                switch ( aElementToken )
388
2.10k
                {
389
700
                case PPT_TOKEN( cTn ):
390
700
                    return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
391
700
                case PPT_TOKEN( nextCondLst ):
392
700
                    return new CondListContext( *this, aElementToken, mpNode, mpNode->getNextCondition() );
393
700
                case PPT_TOKEN( prevCondLst ):
394
700
                    return new CondListContext( *this, aElementToken, mpNode, mpNode->getPrevCondition() );
395
0
                default:
396
0
                    break;
397
2.10k
                }
398
399
0
                return this;
400
2.10k
            }
401
    private:
402
        bool mbConcurrent;
403
        sal_Int32 mnNextAc, mnPrevAc;
404
    };
405
406
    /** CT_TLTimeNodeParallel
407
     *  CT_TLTimeNodeExclusive
408
     */
409
    class ParallelExclTimeNodeContext
410
        : public TimeNodeContext
411
    {
412
    public:
413
        ParallelExclTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
414
                                     const TimeNodePtr & pNode )
415
991
            : TimeNodeContext( rParent, aElement, pNode )
416
991
            {
417
991
            }
418
419
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
420
991
            {
421
991
                switch ( aElementToken )
422
991
                {
423
991
                case PPT_TOKEN( cTn ):
424
991
                    return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
425
0
                default:
426
0
                    break;
427
991
                }
428
429
0
                return this;
430
991
            }
431
432
    protected:
433
434
    };
435
436
    /** CT_TLAnimateColorBehavior */
437
    class AnimColorContext
438
        : public TimeNodeContext
439
    {
440
    public:
441
        AnimColorContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
442
                            const Reference< XFastAttributeList >& xAttribs,
443
                            const TimeNodePtr & pNode ) noexcept
444
12
            : TimeNodeContext( rParent, aElement, pNode )
445
12
            , mnColorSpace( xAttribs->getOptionalValueToken( XML_clrSpc, 0 ) )
446
12
            , mnDir( xAttribs->getOptionalValueToken( XML_dir, 0 ) )
447
12
            , mbHasByColor( false )
448
12
            , m_byColor( AnimationColorSpace::RGB, 0, 0, 0)
449
12
            {
450
12
            }
451
452
        virtual void onEndElement() override
453
12
            {
454
                //xParentNode
455
12
                if( !isCurrentElement( mnElement ) )
456
0
                    return;
457
458
12
                NodePropertyMap & rProps(mpNode->getNodeProperties());
459
12
                rProps[ NP_DIRECTION ] <<= mnDir == XML_cw;
460
12
                rProps[ NP_COLORINTERPOLATION ] <<= mnColorSpace == XML_hsl ? AnimationColorSpace::HSL : AnimationColorSpace::RGB;
461
12
                const GraphicHelper& rGraphicHelper = getFilter().getGraphicHelper();
462
12
                if( maToClr.isUsed() )
463
12
                    mpNode->setTo( Any( maToClr.getColor( rGraphicHelper ) ) );
464
12
                if( maFromClr.isUsed() )
465
0
                    mpNode->setFrom( Any( maFromClr.getColor( rGraphicHelper ) ) );
466
12
                if( mbHasByColor )
467
0
                    mpNode->setBy( m_byColor.get() );
468
12
            }
469
470
            virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
471
24
            {
472
24
                switch ( aElementToken )
473
24
                {
474
0
                case PPT_TOKEN( hsl ):
475
                    // CT_TLByHslColorTransform
476
0
                {
477
0
                    if( mbHasByColor )
478
0
                    {
479
0
                        m_byColor.colorSpace = AnimationColorSpace::HSL;
480
0
                        m_byColor.one = rAttribs.getInteger( XML_h, 0 );
481
0
                        m_byColor.two = rAttribs.getInteger( XML_s, 0 );
482
0
                        m_byColor.three = rAttribs.getInteger( XML_l, 0 );
483
0
                    }
484
0
                    return this;
485
0
                }
486
0
                case PPT_TOKEN( rgb ):
487
0
                {
488
0
                    if( mbHasByColor )
489
0
                    {
490
                        // CT_TLByRgbColorTransform
491
0
                        m_byColor.colorSpace = AnimationColorSpace::RGB;
492
0
                        m_byColor.one = rAttribs.getInteger( XML_r, 0 );
493
0
                        m_byColor.two = rAttribs.getInteger( XML_g, 0 );
494
0
                        m_byColor.three = rAttribs.getInteger( XML_b, 0 );
495
0
                    }
496
0
                    return this;
497
0
                }
498
0
                case PPT_TOKEN( by ):
499
                    // CT_TLByAnimateColorTransform
500
0
                    mbHasByColor = true;
501
0
                    return this;
502
12
                case PPT_TOKEN( cBhvr ):
503
12
                    return new CommonBehaviorContext ( *this, mpNode );
504
12
                case PPT_TOKEN( to ):
505
                    // CT_Color
506
12
                    return new ColorContext(*this, &maToClr);
507
0
                case PPT_TOKEN( from ):
508
                    // CT_Color
509
0
                    return new ColorContext(*this, &maFromClr);
510
511
0
                default:
512
0
                    break;
513
24
                }
514
515
0
                return this;
516
24
            }
517
518
    private:
519
        sal_Int32 mnColorSpace;
520
        sal_Int32 mnDir;
521
        bool mbHasByColor;
522
        AnimColor m_byColor;
523
        oox::drawingml::Color maToClr;
524
        oox::drawingml::Color maFromClr;
525
    };
526
527
    /** CT_TLAnimateBehavior */
528
    class AnimContext
529
        : public TimeNodeContext
530
    {
531
    public:
532
        AnimContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
533
                     const Reference< XFastAttributeList >& xAttribs,
534
                      const TimeNodePtr & pNode ) noexcept
535
64
            : TimeNodeContext( rParent, aElement, pNode )
536
64
            {
537
64
                NodePropertyMap & aProps( pNode->getNodeProperties() );
538
64
                sal_Int32 nCalcMode = xAttribs->getOptionalValueToken( XML_calcmode, 0 );
539
64
                if(nCalcMode)
540
64
                {
541
64
                    sal_Int16 nEnum = 0;
542
64
                    switch(nCalcMode)
543
64
                    {
544
64
                    case XML_lin:
545
64
                        nEnum = AnimationCalcMode::LINEAR;
546
64
                        break;
547
0
                    case XML_discrete:
548
0
                    case XML_fmla:
549
0
                    default:
550
                        // TODO what value is good ?
551
0
                        nEnum = AnimationCalcMode::DISCRETE;
552
0
                        break;
553
64
                    }
554
64
                    aProps[ NP_CALCMODE ] <<= nEnum;
555
64
                }
556
557
64
                msFrom = xAttribs->getOptionalValue(XML_from);
558
64
                msTo = xAttribs->getOptionalValue(XML_to);
559
64
                msBy = xAttribs->getOptionalValue(XML_by);
560
561
64
                mnValueType = xAttribs->getOptionalValueToken( XML_valueType, 0 );
562
64
            }
563
564
        virtual ~AnimContext() noexcept override
565
64
            {
566
64
                if (!msFrom.isEmpty())
567
44
                {
568
44
                    css::uno::Any aAny;
569
44
                    aAny <<= msFrom;
570
44
                    convertAnimationValueWithTimeNode(mpNode, aAny);
571
44
                    mpNode->setFrom(aAny);
572
44
                }
573
574
64
                if (!msTo.isEmpty())
575
44
                {
576
44
                    css::uno::Any aAny;
577
44
                    aAny <<= msTo;
578
44
                    convertAnimationValueWithTimeNode(mpNode, aAny);
579
44
                    mpNode->setTo(aAny);
580
44
                }
581
582
64
                if (!msBy.isEmpty())
583
0
                {
584
0
                    css::uno::Any aAny;
585
0
                    aAny <<= msBy;
586
0
                    convertAnimationValueWithTimeNode(mpNode, aAny);
587
0
                    mpNode->setBy(aAny);
588
0
                }
589
590
64
                int nKeyTimes = maTavList.size();
591
64
                if( nKeyTimes <= 0)
592
44
                    return;
593
594
20
                int i=0;
595
20
                Sequence< double > aKeyTimes( nKeyTimes );
596
20
                auto pKeyTimes = aKeyTimes.getArray();
597
20
                Sequence< Any > aValues( nKeyTimes );
598
20
                auto pValues = aValues.getArray();
599
600
20
                NodePropertyMap & aProps( mpNode->getNodeProperties() );
601
20
                for (auto const& tav : maTavList)
602
40
                {
603
                    // TODO what to do if it is Timing_INFINITE ?
604
40
                    Any aTime = GetTimeAnimateValueTime( tav.msTime );
605
40
                    aTime >>= pKeyTimes[i];
606
40
                    pValues[i] = tav.maValue;
607
40
                    convertAnimationValueWithTimeNode(mpNode, pValues[i]);
608
609
                    // Examine pptx documents and find that only the first tav
610
                    // has the formula set. The formula can be used for the whole.
611
40
                    if (!tav.msFormula.isEmpty())
612
8
                    {
613
8
                        OUString sFormula = tav.msFormula;
614
8
                        (void)convertMeasure(sFormula);
615
8
                        aProps[NP_FORMULA] <<= sFormula;
616
8
                    }
617
618
40
                    ++i;
619
40
                }
620
20
                aProps[ NP_VALUES ] <<= aValues;
621
20
                aProps[ NP_KEYTIMES ] <<= aKeyTimes;
622
20
            }
623
624
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
625
84
            {
626
84
                switch ( aElementToken )
627
84
                {
628
64
                case PPT_TOKEN( cBhvr ):
629
64
                    return new CommonBehaviorContext ( *this, mpNode );
630
20
                case PPT_TOKEN( tavLst ):
631
20
                    return new TimeAnimValueListContext ( *this, maTavList );
632
0
                default:
633
0
                    break;
634
84
                }
635
636
0
                return this;
637
84
            }
638
    private:
639
        sal_Int32              mnValueType;
640
        TimeAnimationValueList maTavList;
641
        OUString msFrom;
642
        OUString msTo;
643
        OUString msBy;
644
    };
645
646
    /** CT_TLAnimateScaleBehavior */
647
    class AnimScaleContext
648
        : public TimeNodeContext
649
    {
650
    public:
651
        AnimScaleContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
652
                            const Reference< XFastAttributeList >& xAttribs,
653
                            const TimeNodePtr & pNode )
654
64
            : TimeNodeContext( rParent, aElement, pNode )
655
64
                , mbZoomContents( false )
656
64
            {
657
64
                AttributeList attribs( xAttribs );
658
                // TODO what to do with mbZoomContents
659
64
                mbZoomContents = attribs.getBool( XML_zoomContents, false );
660
64
                pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
661
64
                    <<= sal_Int16(AnimationTransformType::SCALE);
662
64
            }
663
664
        virtual void onEndElement() override
665
172
            {
666
172
                if( !isCurrentElement( mnElement ) )
667
108
                    return;
668
669
64
                if( maTo.hasValue() )
670
60
                {
671
60
                    mpNode->setTo( maTo );
672
60
                }
673
64
                if( maBy.hasValue() )
674
4
                {
675
4
                    mpNode->setBy( maBy );
676
4
                }
677
64
                if( maFrom.hasValue() )
678
44
                {
679
44
                    mpNode->setFrom( maFrom );
680
44
                }
681
64
            }
682
683
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
684
172
            {
685
172
                switch ( aElementToken )
686
172
                {
687
64
                case PPT_TOKEN( cBhvr ):
688
64
                    return new CommonBehaviorContext ( *this, mpNode );
689
60
                case PPT_TOKEN( to ):
690
60
                {
691
                    // CT_TLPoint
692
60
                    maTo = convertPointPercent(GetPointPercent(rAttribs.getFastAttributeList()));
693
60
                    return this;
694
0
                }
695
44
                case PPT_TOKEN( from ):
696
44
                {
697
                    // CT_TLPoint
698
44
                    maFrom  = convertPointPercent(GetPointPercent(rAttribs.getFastAttributeList()));
699
44
                    return this;
700
0
                }
701
4
                case PPT_TOKEN( by ):
702
4
                {
703
                    // CT_TLPoint
704
4
                    css::awt::Point aPoint = GetPointPercent(rAttribs.getFastAttributeList());
705
                    // We got ending values instead of offset values, so subtract 100% from them.
706
4
                    aPoint.X -= 100000;
707
4
                    aPoint.Y -= 100000;
708
4
                    maBy = convertPointPercent(aPoint);
709
4
                    return this;
710
0
                }
711
0
                default:
712
0
                    break;
713
172
                }
714
715
0
                return this;
716
172
            }
717
    private:
718
        Any maBy;
719
        Any maFrom;
720
        Any maTo;
721
        bool mbZoomContents;
722
    };
723
724
    /** CT_TLAnimateRotationBehavior */
725
    class AnimRotContext
726
        : public TimeNodeContext
727
    {
728
    public:
729
        AnimRotContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
730
                        const Reference< XFastAttributeList >& xAttribs,
731
                         const TimeNodePtr & pNode ) noexcept
732
2
            : TimeNodeContext( rParent, aElement, pNode )
733
2
            {
734
2
                AttributeList attribs( xAttribs );
735
736
2
                pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
737
2
                    <<= sal_Int16(AnimationTransformType::ROTATE);
738
                // see also DFF_msofbtAnimateRotationData in
739
                // sd/source/filter/ppt/pptinanimations.cxx
740
2
                if(attribs.hasAttribute( XML_by ) )
741
2
                {
742
2
                    double fBy = attribs.getDouble( XML_by, 0.0 ) / PER_DEGREE; //1 PowerPoint-angle-unit = 1/60000 degree
743
2
                    pNode->setBy( Any( fBy ) );
744
2
                }
745
2
                if(attribs.hasAttribute( XML_from ) )
746
0
                {
747
0
                    double fFrom = attribs.getDouble( XML_from, 0.0 ) / PER_DEGREE;
748
0
                    pNode->setFrom( Any( fFrom ) );
749
0
                }
750
2
                if(attribs.hasAttribute( XML_to ) )
751
0
                {
752
0
                    double fTo = attribs.getDouble( XML_to, 0.0 ) / PER_DEGREE;
753
0
                    pNode->setTo( Any( fTo ) );
754
0
                }
755
2
            }
756
757
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
758
2
            {
759
2
                switch ( aElementToken )
760
2
                {
761
2
                case PPT_TOKEN( cBhvr ):
762
2
                    return new CommonBehaviorContext ( *this, mpNode );
763
0
                default:
764
0
                    break;
765
2
                }
766
767
0
                return this;
768
2
            }
769
    };
770
771
    /** CT_TLAnimateMotionBehavior */
772
    class AnimMotionContext
773
        : public TimeNodeContext
774
    {
775
    public:
776
        AnimMotionContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
777
                         const Reference< XFastAttributeList >& xAttribs,
778
                          const TimeNodePtr & pNode ) noexcept
779
1
            : TimeNodeContext( rParent, aElement, pNode )
780
1
            {
781
1
                pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
782
1
                    <<= sal_Int16(AnimationTransformType::TRANSLATE);
783
784
1
                AttributeList attribs( xAttribs );
785
1
                sal_Int32 nOrigin = xAttribs->getOptionalValueToken( XML_origin, 0 );
786
1
                if( nOrigin != 0 )
787
1
                {
788
1
                    switch(nOrigin)
789
1
                    {
790
1
                    case XML_layout:
791
1
                    case XML_parent:
792
1
                        break;
793
1
                    }
794
                    // TODO
795
1
                }
796
797
1
                OUString aStr = xAttribs->getOptionalValue( XML_path );
798
                // E can appear inside a number, so we only check for its presence at the end
799
1
                aStr = aStr.trim();
800
1
                if (aStr.endsWith("E"))
801
0
                    aStr = aStr.copy(0, aStr.getLength() - 1);
802
1
                aStr = aStr.trim();
803
1
                pNode->getNodeProperties()[ NP_PATH ] <<= aStr;
804
1
                mnPathEditMode = xAttribs->getOptionalValueToken( XML_pathEditMode, 0 );
805
1
                msPtsTypes = xAttribs->getOptionalValue( XML_ptsTypes );
806
1
                mnAngle = attribs.getInteger( XML_rAng, 0 );
807
                // TODO make sure the units are right. Likely not.
808
1
            }
809
810
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
811
2
            {
812
2
                switch ( aElementToken )
813
2
                {
814
1
                case PPT_TOKEN( cBhvr ):
815
1
                    return new CommonBehaviorContext ( *this, mpNode );
816
0
                case PPT_TOKEN( to ):
817
0
                {
818
                    // CT_TLPoint
819
0
                    awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
820
0
                    Any rAny;
821
0
                    rAny <<= p.X;
822
0
                    rAny <<= p.Y;
823
0
                    mpNode->setTo( rAny );
824
0
                    return this;
825
0
                }
826
0
                case PPT_TOKEN( from ):
827
0
                {
828
                    // CT_TLPoint
829
0
                    awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
830
0
                    Any rAny;
831
0
                    rAny <<= p.X;
832
0
                    rAny <<= p.Y;
833
0
                    mpNode->setFrom( rAny );
834
0
                    return this;
835
0
                }
836
0
                case PPT_TOKEN( by ):
837
0
                {
838
                    // CT_TLPoint
839
0
                    awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
840
0
                    Any rAny;
841
0
                    rAny <<= p.X;
842
0
                    rAny <<= p.Y;
843
0
                    mpNode->setBy( rAny );
844
0
                    return this;
845
0
                }
846
1
                case PPT_TOKEN( rCtr ):
847
1
                {
848
                    // CT_TLPoint
849
1
                    awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
850
                    // TODO push
851
1
                    (void)p;
852
1
                    return this;
853
0
                }
854
0
                default:
855
0
                    break;
856
2
                }
857
858
0
                return this;
859
2
            }
860
    private:
861
        OUString msPtsTypes;
862
        sal_Int32 mnPathEditMode;
863
        sal_Int32 mnAngle;
864
    };
865
866
    /** CT_TLAnimateEffectBehavior */
867
    class AnimEffectContext
868
        : public TimeNodeContext
869
    {
870
    public:
871
        AnimEffectContext( FragmentHandler2 const & rParent, sal_Int32  aElement,
872
                             const Reference< XFastAttributeList >& xAttribs,
873
                             const TimeNodePtr & pNode ) noexcept
874
43
            : TimeNodeContext( rParent, aElement, pNode )
875
43
            {
876
43
                sal_Int32 nDir = xAttribs->getOptionalValueToken( XML_transition, 0 );
877
43
                OUString sFilter = xAttribs->getOptionalValue( XML_filter );
878
                // TODO
879
//              OUString sPrList = xAttribs->getOptionalValue( XML_prLst );
880
881
43
                if( !sFilter.isEmpty() )
882
43
                {
883
43
                    SlideTransition aFilter( sFilter );
884
43
                    aFilter.setMode( nDir != XML_out );
885
43
                    pNode->setTransitionFilter( aFilter );
886
43
                }
887
43
            }
888
889
        virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
890
43
            {
891
43
                switch ( aElementToken )
892
43
                {
893
43
                case PPT_TOKEN( cBhvr ):
894
43
                    return new CommonBehaviorContext ( *this, mpNode );
895
0
                case PPT_TOKEN( progress ):
896
0
                    return new AnimVariantContext( *this, aElementToken, maProgress );
897
                    // TODO handle it.
898
0
                default:
899
0
                    break;
900
43
                }
901
902
0
                return this;
903
43
            }
904
    private:
905
        Any maProgress;
906
    };
907
908
    }
909
910
    rtl::Reference<TimeNodeContext> TimeNodeContext::makeContext(
911
            FragmentHandler2 const & rParent, sal_Int32  aElement,
912
            const Reference< XFastAttributeList >& xAttribs,
913
            const TimeNodePtr & pNode )
914
1.98k
    {
915
1.98k
        rtl::Reference<TimeNodeContext> pCtx;
916
1.98k
        switch( aElement )
917
1.98k
        {
918
12
        case PPT_TOKEN( animClr ):
919
12
            pCtx = new AnimColorContext( rParent, aElement, xAttribs, pNode );
920
12
            break;
921
700
        case PPT_TOKEN( seq ):
922
700
            pCtx = new SequenceTimeNodeContext( rParent, aElement, xAttribs, pNode );
923
700
            break;
924
991
        case PPT_TOKEN( par ):
925
991
        case PPT_TOKEN( excl ):
926
991
            pCtx = new ParallelExclTimeNodeContext( rParent, aElement, pNode );
927
991
            break;
928
64
        case PPT_TOKEN( anim ):
929
64
            pCtx = new AnimContext ( rParent, aElement, xAttribs, pNode );
930
64
            break;
931
43
        case PPT_TOKEN( animEffect ):
932
43
            pCtx = new AnimEffectContext( rParent, aElement, xAttribs, pNode );
933
43
            break;
934
1
        case PPT_TOKEN( animMotion ):
935
1
            pCtx = new AnimMotionContext( rParent, aElement, xAttribs, pNode );
936
1
            break;
937
2
        case PPT_TOKEN( animRot ):
938
2
            pCtx = new AnimRotContext( rParent, aElement, xAttribs, pNode );
939
2
            break;
940
64
        case PPT_TOKEN( animScale ):
941
64
            pCtx = new AnimScaleContext( rParent, aElement, xAttribs, pNode );
942
64
            break;
943
0
        case PPT_TOKEN( cmd ):
944
0
            pCtx = new CmdTimeNodeContext( rParent, aElement, xAttribs, pNode );
945
0
            break;
946
109
        case PPT_TOKEN( set ):
947
109
            pCtx = new SetTimeNodeContext( rParent, aElement, pNode );
948
109
            break;
949
0
        case PPT_TOKEN( audio ):
950
0
        case PPT_TOKEN( video ):
951
0
            pCtx = new MediaNodeContext( rParent, aElement, xAttribs, pNode );
952
0
            break;
953
0
        default:
954
0
            break;
955
1.98k
        }
956
1.98k
        return pCtx;
957
1.98k
    }
958
959
    TimeNodeContext::TimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
960
            TimeNodePtr pNode ) noexcept
961
7.45k
        : FragmentHandler2( rParent )
962
7.45k
        , mnElement( aElement )
963
7.45k
        , mpNode(std::move( pNode ))
964
7.45k
    {
965
7.45k
    }
966
967
    TimeNodeContext::~TimeNodeContext( ) noexcept
968
7.45k
    {
969
970
7.45k
    }
971
972
    TimeNodeListContext::TimeNodeListContext( FragmentHandler2 const & rParent, TimeNodePtrList & aList )
973
        noexcept
974
2.13k
        : FragmentHandler2( rParent )
975
2.13k
            , maList( aList )
976
2.13k
    {
977
2.13k
    }
978
979
    TimeNodeListContext::~TimeNodeListContext( ) noexcept
980
2.13k
    {
981
2.13k
    }
982
983
    ::oox::core::ContextHandlerRef TimeNodeListContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
984
1.98k
    {
985
1.98k
        sal_Int16 nNodeType;
986
987
1.98k
        switch( aElementToken )
988
1.98k
        {
989
700
        case PPT_TOKEN( seq ):
990
700
            nNodeType = AnimationNodeType::SEQ;
991
700
            break;
992
991
        case PPT_TOKEN( par ):
993
991
        case PPT_TOKEN( excl ):
994
            // TODO pick the right type. We choose parallel for now as
995
            // there does not seem to be an "Exclusive"
996
991
            nNodeType = AnimationNodeType::PAR;
997
991
            break;
998
64
        case PPT_TOKEN( anim ):
999
64
            nNodeType = AnimationNodeType::ANIMATE;
1000
64
            break;
1001
12
        case PPT_TOKEN( animClr ):
1002
12
            nNodeType = AnimationNodeType::ANIMATECOLOR;
1003
12
            break;
1004
43
        case PPT_TOKEN( animEffect ):
1005
43
            nNodeType = AnimationNodeType::TRANSITIONFILTER;
1006
43
            break;
1007
1
        case PPT_TOKEN( animMotion ):
1008
1
            nNodeType = AnimationNodeType::ANIMATEMOTION;
1009
1
            break;
1010
2
        case PPT_TOKEN( animRot ):
1011
66
        case PPT_TOKEN( animScale ):
1012
66
            nNodeType = AnimationNodeType::ANIMATETRANSFORM;
1013
66
            break;
1014
0
        case PPT_TOKEN( cmd ):
1015
0
            nNodeType = AnimationNodeType::COMMAND;
1016
0
            break;
1017
109
        case PPT_TOKEN( set ):
1018
109
            nNodeType = AnimationNodeType::SET;
1019
109
            break;
1020
0
        case PPT_TOKEN( audio ):
1021
0
            nNodeType = AnimationNodeType::AUDIO;
1022
0
            break;
1023
0
        case PPT_TOKEN( video ):
1024
0
            nNodeType = AnimationNodeType::AUDIO;
1025
0
            SAL_WARN("oox.ppt", "OOX: video requested, gave Audio instead" );
1026
0
            break;
1027
1028
0
        default:
1029
0
            nNodeType = AnimationNodeType::CUSTOM;
1030
0
            SAL_INFO("oox.ppt", "unhandled token " << aElementToken);
1031
0
            break;
1032
1.98k
        }
1033
1034
1.98k
        TimeNodePtr pNode = std::make_shared<TimeNode>(nNodeType);
1035
1.98k
        maList.push_back( pNode );
1036
1.98k
        rtl::Reference<FragmentHandler2> pContext = TimeNodeContext::makeContext( *this, aElementToken, rAttribs.getFastAttributeList(), pNode );
1037
1038
1.98k
        return pContext ? pContext : this;
1039
1.98k
    }
1040
1041
}
1042
1043
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */