bump product version to 6.3.0.0.beta1
[LibreOffice.git] / sd / source / filter / eppt / pptx-animations.cxx
blob1a35c7777e2a38856c7d07863a9e9fbf5b39d018
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 <o3tl/any.hxx>
21 #include <oox/token/tokens.hxx>
22 #include "epptooxml.hxx"
23 #include <sax/fshelper.hxx>
24 #include <sal/log.hxx>
26 #include <com/sun/star/animations/AnimationAdditiveMode.hpp>
27 #include <com/sun/star/animations/AnimationCalcMode.hpp>
28 #include <com/sun/star/animations/AnimationFill.hpp>
29 #include <com/sun/star/animations/AnimationNodeType.hpp>
30 #include <com/sun/star/animations/AnimationRestart.hpp>
31 #include <com/sun/star/animations/AnimationTransformType.hpp>
32 #include <com/sun/star/animations/AnimationValueType.hpp>
33 #include <com/sun/star/animations/AnimationColorSpace.hpp>
34 #include <com/sun/star/animations/Event.hpp>
35 #include <com/sun/star/animations/EventTrigger.hpp>
36 #include <com/sun/star/animations/Timing.hpp>
37 #include <com/sun/star/animations/ValuePair.hpp>
38 #include <com/sun/star/animations/XAnimateMotion.hpp>
39 #include <com/sun/star/animations/XAnimateTransform.hpp>
40 #include <com/sun/star/animations/XAnimationNode.hpp>
41 #include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
42 #include <com/sun/star/animations/XAnimateColor.hpp>
43 #include <com/sun/star/animations/XCommand.hpp>
44 #include <com/sun/star/animations/XAudio.hpp>
45 #include <com/sun/star/animations/XTransitionFilter.hpp>
46 #include <com/sun/star/animations/XIterateContainer.hpp>
47 #include <com/sun/star/container/XEnumerationAccess.hpp>
48 #include <com/sun/star/presentation/EffectCommands.hpp>
49 #include <com/sun/star/presentation/EffectNodeType.hpp>
50 #include <com/sun/star/presentation/EffectPresetClass.hpp>
51 #include <com/sun/star/presentation/ParagraphTarget.hpp>
52 #include <com/sun/star/presentation/TextAnimationType.hpp>
53 #include <com/sun/star/text/XSimpleText.hpp>
54 #include <com/sun/star/drawing/XShape.hpp>
55 #include <oox/export/utils.hxx>
56 #include <oox/ppt/pptfilterhelpers.hxx>
57 #include <basegfx/polygon/b2dpolypolygontools.hxx>
59 #include "pptexanimations.hxx"
60 #include "pptx-animations.hxx"
61 #include "../ppt/pptanimations.hxx"
62 #include <comphelper/stl_types.hxx>
64 using namespace ::com::sun::star::animations;
65 using namespace ::com::sun::star::container;
66 using namespace ::com::sun::star::presentation;
67 using namespace ::com::sun::star::uno;
68 using namespace ::ppt;
69 using namespace oox::drawingml;
70 using namespace oox::core;
71 using namespace oox;
73 using ::com::sun::star::beans::NamedValue;
74 using ::com::sun::star::drawing::XDrawPage;
75 using ::com::sun::star::drawing::XShape;
76 using ::com::sun::star::text::XSimpleText;
77 using ::sax_fastparser::FSHelperPtr;
79 namespace
81 void WriteAnimationProperty(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken = 0)
83 if (!rAny.hasValue())
84 return;
86 ValuePair aPair;
88 if (rAny >>= aPair)
90 double x, y;
91 if ((aPair.First >>= x) && (aPair.Second >>= y))
93 if (nToken == XML_by)
95 // MS needs ending values but we have offset values.
96 x += 1.0;
97 y += 1.0;
99 pFS->singleElementNS(XML_p, nToken, XML_x, OString::number(x * 100000), XML_y,
100 OString::number(y * 100000));
102 return;
105 sal_uInt32 nRgb;
106 double fDouble;
108 TypeClass aClass = rAny.getValueType().getTypeClass();
109 bool bWriteToken
110 = nToken
111 && (aClass == TypeClass_LONG || aClass == TypeClass_DOUBLE || aClass == TypeClass_STRING);
113 if (bWriteToken)
114 pFS->startElementNS(XML_p, nToken);
116 switch (rAny.getValueType().getTypeClass())
118 case TypeClass_LONG:
119 rAny >>= nRgb;
120 pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nRgb));
121 break;
122 case TypeClass_DOUBLE:
123 rAny >>= fDouble;
124 pFS->singleElementNS(XML_p, XML_fltVal, XML_val, OString::number(fDouble));
125 break;
126 case TypeClass_STRING:
127 pFS->singleElementNS(XML_p, XML_strVal, XML_val,
128 (*o3tl::doAccess<OUString>(rAny)).toUtf8());
129 break;
130 default:
131 break;
134 if (bWriteToken)
135 pFS->endElementNS(XML_p, nToken);
138 void WriteAnimateColorColor(const FSHelperPtr& pFS, const Any& rAny, sal_Int32 nToken)
140 if (!rAny.hasValue())
141 return;
143 sal_Int32 nColor = 0;
144 if (rAny >>= nColor)
146 pFS->startElementNS(XML_p, nToken);
148 if (nToken == XML_by)
150 // CT_TLByRgbColorTransform
151 SAL_WARN("sd.eppt", "Export p:rgb in p:by of animClr isn't implemented yet.");
153 else
155 // CT_Color
156 pFS->singleElementNS(XML_a, XML_srgbClr, XML_val, I32SHEX(nColor));
159 pFS->endElementNS(XML_p, nToken);
162 Sequence<double> aHSL(3);
163 if (!(rAny >>= aHSL))
164 return;
166 pFS->startElementNS(XML_p, nToken);
168 if (nToken == XML_by)
170 // CT_TLByHslColorTransform
171 pFS->singleElementNS(XML_p, XML_hsl, XML_h, OString::number(aHSL[0] * 60000), // ST_Angel
172 XML_s, OString::number(aHSL[1] * 100000), XML_l,
173 OString::number(aHSL[2] * 100000));
175 else
177 // CT_Color
178 SAL_WARN("sd.eppt", "Export p:hsl in p:from or p:to of animClr isn't implemented yet.");
181 pFS->endElementNS(XML_p, nToken);
184 void WriteAnimateTo(const FSHelperPtr& pFS, const Any& rValue, const OUString& rAttributeName)
186 if (!rValue.hasValue())
187 return;
189 SAL_INFO("sd.eppt", "to attribute name: " << rAttributeName.toUtf8());
191 WriteAnimationProperty(pFS, AnimationExporter::convertAnimateValue(rValue, rAttributeName),
192 XML_to);
195 void WriteAnimateValues(const FSHelperPtr& pFS, const Reference<XAnimate>& rXAnimate)
197 const Sequence<double> aKeyTimes = rXAnimate->getKeyTimes();
198 if (!aKeyTimes.hasElements())
199 return;
200 const Sequence<Any> aValues = rXAnimate->getValues();
201 const OUString& sFormula = rXAnimate->getFormula();
202 const OUString& rAttributeName = rXAnimate->getAttributeName();
204 SAL_INFO("sd.eppt", "animate values, formula: " << sFormula.toUtf8());
206 pFS->startElementNS(XML_p, XML_tavLst);
208 for (int i = 0; i < aKeyTimes.getLength(); i++)
210 SAL_INFO("sd.eppt", "animate value " << i << ": " << aKeyTimes[i]);
211 if (aValues[i].hasValue())
213 pFS->startElementNS(XML_p, XML_tav, XML_fmla,
214 sFormula.isEmpty() ? nullptr : sFormula.toUtf8().getStr(), XML_tm,
215 OString::number(static_cast<sal_Int32>(aKeyTimes[i] * 100000.0)));
216 pFS->startElementNS(XML_p, XML_val);
217 ValuePair aPair;
218 if (aValues[i] >>= aPair)
220 WriteAnimationProperty(
221 pFS, AnimationExporter::convertAnimateValue(aPair.First, rAttributeName));
222 WriteAnimationProperty(
223 pFS, AnimationExporter::convertAnimateValue(aPair.Second, rAttributeName));
225 else
226 WriteAnimationProperty(
227 pFS, AnimationExporter::convertAnimateValue(aValues[i], rAttributeName));
229 pFS->endElementNS(XML_p, XML_val);
230 pFS->endElementNS(XML_p, XML_tav);
234 pFS->endElementNS(XML_p, XML_tavLst);
237 // Write condition list ( either prevCondlst or nextCondlst ) of Seq.
238 void WriteAnimationCondListForSeq(const FSHelperPtr& pFS, sal_Int32 nToken)
240 const char* pEvent = (nToken == XML_prevCondLst) ? "onPrev" : "onNext";
242 pFS->startElementNS(XML_p, nToken);
243 pFS->startElementNS(XML_p, XML_cond, XML_evt, pEvent);
244 pFS->startElementNS(XML_p, XML_tgtEl);
245 pFS->singleElementNS(XML_p, XML_sldTgt);
246 pFS->endElementNS(XML_p, XML_tgtEl);
247 pFS->endElementNS(XML_p, XML_cond);
248 pFS->endElementNS(XML_p, nToken);
251 const char* convertEventTrigger(sal_Int16 nTrigger)
253 const char* pEvent = nullptr;
254 switch (nTrigger)
256 case EventTrigger::ON_NEXT:
257 pEvent = "onNext";
258 break;
259 case EventTrigger::ON_PREV:
260 pEvent = "onPrev";
261 break;
262 case EventTrigger::BEGIN_EVENT:
263 pEvent = "begin";
264 break;
265 case EventTrigger::END_EVENT:
266 pEvent = "end";
267 break;
268 case EventTrigger::ON_BEGIN:
269 pEvent = "onBegin";
270 break;
271 case EventTrigger::ON_END:
272 pEvent = "onEnd";
273 break;
274 case EventTrigger::ON_CLICK:
275 pEvent = "onClick";
276 break;
277 case EventTrigger::ON_DBL_CLICK:
278 pEvent = "onDblClick";
279 break;
280 case EventTrigger::ON_STOP_AUDIO:
281 pEvent = "onStopAudio";
282 break;
283 case EventTrigger::ON_MOUSE_ENTER:
284 pEvent = "onMouseOver"; // not exact?
285 break;
286 case EventTrigger::ON_MOUSE_LEAVE:
287 pEvent = "onMouseOut";
288 break;
290 return pEvent;
293 void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttributeName)
295 if (rAttributeName.isEmpty())
296 return;
298 pFS->startElementNS(XML_p, XML_attrNameLst);
300 SAL_INFO("sd.eppt", "write attribute name: " << rAttributeName.toUtf8());
302 if (rAttributeName == "X;Y")
304 pFS->startElementNS(XML_p, XML_attrName);
305 pFS->writeEscaped("ppt_x");
306 pFS->endElementNS(XML_p, XML_attrName);
308 pFS->startElementNS(XML_p, XML_attrName);
309 pFS->writeEscaped("ppt_y");
310 pFS->endElementNS(XML_p, XML_attrName);
312 else
314 const oox::ppt::ImplAttributeNameConversion* attrConv
315 = oox::ppt::getAttributeConversionList();
316 const char* pAttribute = nullptr;
318 while (attrConv->mpAPIName != nullptr)
320 if (rAttributeName.equalsAscii(attrConv->mpAPIName))
322 pAttribute = attrConv->mpMSName;
323 break;
325 attrConv++;
328 if (pAttribute)
330 pFS->startElementNS(XML_p, XML_attrName);
331 pFS->writeEscaped(pAttribute);
332 pFS->endElementNS(XML_p, XML_attrName);
334 else
336 SAL_WARN("sd.eppt", "unhandled animation attribute name: " << rAttributeName);
340 pFS->endElementNS(XML_p, XML_attrNameLst);
343 bool isValidTarget(const Any& rTarget)
345 Reference<XShape> xShape;
347 if ((rTarget >>= xShape) && xShape.is())
348 return true;
350 ParagraphTarget aParagraphTarget;
352 return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
355 /// extract ooxml node type from a XAnimationNode.
356 sal_Int32 extractNodeType(const Reference<XAnimationNode>& rXNode)
358 sal_Int16 nType = rXNode->getType();
359 sal_Int32 xmlNodeType = -1;
360 switch (nType)
362 case AnimationNodeType::ITERATE:
363 case AnimationNodeType::PAR:
364 xmlNodeType = XML_par;
365 break;
366 case AnimationNodeType::SEQ:
367 xmlNodeType = XML_seq;
368 break;
369 case AnimationNodeType::ANIMATE:
370 xmlNodeType = XML_anim;
371 break;
372 case AnimationNodeType::ANIMATEMOTION:
373 xmlNodeType = XML_animMotion;
374 break;
375 case AnimationNodeType::ANIMATETRANSFORM:
377 Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
378 if (xTransform.is())
380 if (xTransform->getTransformType() == AnimationTransformType::SCALE)
381 xmlNodeType = XML_animScale;
382 else if (xTransform->getTransformType() == AnimationTransformType::ROTATE)
383 xmlNodeType = XML_animRot;
385 break;
387 case AnimationNodeType::ANIMATECOLOR:
388 xmlNodeType = XML_animClr;
389 break;
390 case AnimationNodeType::SET:
391 xmlNodeType = XML_set;
392 break;
393 case AnimationNodeType::TRANSITIONFILTER:
394 xmlNodeType = XML_animEffect;
395 break;
396 case AnimationNodeType::COMMAND:
397 xmlNodeType = XML_cmd;
398 break;
399 case AnimationNodeType::AUDIO:
400 xmlNodeType = XML_audio;
401 break;
402 default:
403 SAL_WARN("sd.eppt", "unhandled animation node: " << nType);
404 break;
406 return xmlNodeType;
409 /// Convert AnimationRestart to ST_TLTimeNodeRestartType value.
410 const char* convertAnimationRestart(sal_Int16 nRestart)
412 const char* pRestart = nullptr;
413 switch (nRestart)
415 case AnimationRestart::ALWAYS:
416 pRestart = "always";
417 break;
418 case AnimationRestart::WHEN_NOT_ACTIVE:
419 pRestart = "whenNotActive";
420 break;
421 case AnimationRestart::NEVER:
422 pRestart = "never";
423 break;
425 return pRestart;
428 /// Convert EffectNodeType to ST_TLTimeNodeType
429 const char* convertEffectNodeType(sal_Int16 nType)
431 const char* pNodeType = nullptr;
432 switch (nType)
434 case EffectNodeType::TIMING_ROOT:
435 pNodeType = "tmRoot";
436 break;
437 case EffectNodeType::MAIN_SEQUENCE:
438 pNodeType = "mainSeq";
439 break;
440 case EffectNodeType::ON_CLICK:
441 pNodeType = "clickEffect";
442 break;
443 case EffectNodeType::AFTER_PREVIOUS:
444 pNodeType = "afterEffect";
445 break;
446 case EffectNodeType::WITH_PREVIOUS:
447 pNodeType = "withEffect";
448 break;
449 case EffectNodeType::INTERACTIVE_SEQUENCE:
450 pNodeType = "interactiveSeq";
451 break;
453 return pNodeType;
456 /// Convert EffectPresetClass to ST_TLTimeNodePresetClassType
457 const char* convertEffectPresetClass(sal_Int16 nPresetClass)
459 const char* pPresetClass = nullptr;
460 switch (nPresetClass)
462 case EffectPresetClass::ENTRANCE:
463 pPresetClass = "entr";
464 break;
465 case EffectPresetClass::EXIT:
466 pPresetClass = "exit";
467 break;
468 case EffectPresetClass::EMPHASIS:
469 pPresetClass = "emph";
470 break;
471 case EffectPresetClass::MOTIONPATH:
472 pPresetClass = "path";
473 break;
474 case EffectPresetClass::OLEACTION:
475 pPresetClass = "verb"; // ?
476 break;
477 case EffectPresetClass::MEDIACALL:
478 pPresetClass = "mediacall";
479 break;
481 return pPresetClass;
484 /// convert AnimationFill to ST_TLTimeNodeFillType.
485 const char* convertAnimationFill(sal_Int16 nFill)
487 const char* pFill = nullptr;
488 switch (nFill)
490 case AnimationFill::FREEZE:
491 pFill = "hold";
492 break;
493 case AnimationFill::HOLD:
494 pFill = "hold";
495 break;
496 case AnimationFill::REMOVE:
497 pFill = "remove";
498 break;
499 case AnimationFill::TRANSITION:
500 pFill = "transition";
501 break;
503 return pFill;
506 /// Convert TextAnimationType to ST_IterateType.
507 const char* convertTextAnimationType(sal_Int16 nType)
509 const char* sType = nullptr;
510 switch (nType)
512 case TextAnimationType::BY_PARAGRAPH:
513 sType = "el";
514 break;
515 case TextAnimationType::BY_LETTER:
516 sType = "lt";
517 break;
518 case TextAnimationType::BY_WORD:
519 default:
520 sType = "wd";
521 break;
523 return sType;
526 class NodeContext;
528 typedef std::unique_ptr<NodeContext> NodeContextPtr;
530 class NodeContext
532 const Reference<XAnimationNode> mxNode;
533 const bool mbMainSeqChild;
535 std::vector<NodeContextPtr> maChildNodes;
536 // if the node has valid target or contains at least one valid target.
537 bool mbValid;
539 // Attributes initialized from mxNode->getUserData().
540 sal_Int16 mnEffectNodeType;
541 sal_Int16 mnEffectPresetClass;
542 OUString msEffectPresetId;
543 OUString msEffectPresetSubType;
545 /// constructor helper for initializing user datas.
546 void initUserData();
548 /// constructor helper to initialize maChildNodes.
549 /// return true if at least one childnode is valid.
550 bool initChildNodes();
552 /// constructor helper to initialize mbValid
553 void initValid(bool bHasValidChild, bool bIsIterateChild);
555 public:
556 NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild, bool bIsIterateChild);
557 const Reference<XAnimationNode>& getNode() const { return mxNode; }
558 bool isMainSeqChild() const { return mbMainSeqChild; }
559 sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
560 sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
561 const OUString& getEffectPresetId() const { return msEffectPresetId; }
562 const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
563 bool isValid() const { return mbValid; }
564 const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
565 Any getCondition(bool bBegin) const;
568 struct Cond
570 OString msDelay;
571 const char* mpEvent;
572 Reference<XShape> mxShape;
573 Reference<XAnimationNode> mxNode;
575 Cond(const Any& rAny, bool bIsMainSeqChild);
577 bool isValid() { return msDelay.getLength() || mpEvent; }
578 const char* getDelay() const { return msDelay.getLength() ? msDelay.getStr() : nullptr; }
581 Cond::Cond(const Any& rAny, bool bIsMainSeqChild)
582 : mpEvent(nullptr)
584 bool bHasFDelay = false;
585 double fDelay = 0;
586 Timing eTiming;
587 Event aEvent;
589 if (rAny >>= eTiming)
591 if (eTiming == Timing_INDEFINITE)
592 msDelay = "indefinite";
594 else if (rAny >>= aEvent)
596 if (aEvent.Trigger == EventTrigger::ON_NEXT && bIsMainSeqChild)
597 msDelay = "indefinite";
598 else
600 mpEvent = convertEventTrigger(aEvent.Trigger);
601 if (!(aEvent.Source >>= mxShape))
602 aEvent.Source >>= mxNode;
604 if (aEvent.Offset >>= fDelay)
605 bHasFDelay = true;
608 else if (rAny >>= fDelay)
609 bHasFDelay = true;
611 if (bHasFDelay)
613 sal_Int32 nDelay = static_cast<sal_uInt32>(fDelay * 1000.0);
614 msDelay = OString::number(nDelay);
618 class PPTXAnimationExport
620 void WriteAnimationNode(const NodeContextPtr& pContext);
621 void WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType);
622 void WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo = true);
623 void WriteAnimationNodeSeq();
624 void WriteAnimationNodeEffect();
625 void WriteAnimationNodeCommand();
626 void WriteAnimationNodeAudio();
627 void WriteAnimationNodeCommonPropsStart();
628 void WriteAnimationTarget(const Any& rTarget);
629 void WriteAnimationCondList(const Any& rAny, sal_Int32 nToken);
630 void WriteAnimationCond(const Cond& rCond);
631 bool isMainSeqChild();
632 const Reference<XAnimationNode>& getCurrentNode();
634 PowerPointExport& mrPowerPointExport;
635 const FSHelperPtr& mpFS;
636 const NodeContext* mpContext;
638 std::map<Reference<XAnimationNode>, sal_Int32> maAnimationNodeIdMap;
639 sal_Int32 GetNextAnimationNodeId(const Reference<XAnimationNode>& rNode);
640 sal_Int32 GetAnimationNodeId(const Reference<XAnimationNode>& rNode);
642 public:
643 PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS);
644 void WriteAnimations(const Reference<XDrawPage>& rXDrawPage);
648 namespace oox
650 namespace core
652 void WriteAnimations(const FSHelperPtr& pFS, const Reference<XDrawPage>& rXDrawPage,
653 PowerPointExport& rExport)
655 PPTXAnimationExport aAnimationExport(rExport, pFS);
656 aAnimationExport.WriteAnimations(rXDrawPage);
661 PPTXAnimationExport::PPTXAnimationExport(PowerPointExport& rExport, const FSHelperPtr& pFS)
662 : mrPowerPointExport(rExport)
663 , mpFS(pFS)
664 , mpContext(nullptr)
668 bool PPTXAnimationExport::isMainSeqChild()
670 assert(mpContext);
671 return mpContext->isMainSeqChild();
674 const Reference<XAnimationNode>& PPTXAnimationExport::getCurrentNode()
676 assert(mpContext);
677 return mpContext->getNode();
680 void PPTXAnimationExport::WriteAnimationTarget(const Any& rTarget)
682 sal_Int32 nParagraph = -1;
683 bool bParagraphTarget = false;
685 Reference<XShape> rXShape;
686 rTarget >>= rXShape;
688 if (!rXShape.is())
690 ParagraphTarget aParagraphTarget;
691 if (rTarget >>= aParagraphTarget)
692 rXShape = aParagraphTarget.Shape;
693 if (rXShape.is())
695 nParagraph = static_cast<sal_Int32>(aParagraphTarget.Paragraph);
696 Reference<XSimpleText> xText(rXShape, UNO_QUERY);
697 if (xText.is())
699 bParagraphTarget = true;
704 if (!rXShape.is())
705 return;
707 sal_Int32 nShapeID = mrPowerPointExport.GetShapeID(rXShape);
709 mpFS->startElementNS(XML_p, XML_tgtEl);
710 mpFS->startElementNS(XML_p, XML_spTgt, XML_spid, OString::number(nShapeID));
711 if (bParagraphTarget)
713 mpFS->startElementNS(XML_p, XML_txEl);
714 mpFS->singleElementNS(XML_p, XML_pRg, XML_st, OString::number(nParagraph), XML_end,
715 OString::number(nParagraph));
716 mpFS->endElementNS(XML_p, XML_txEl);
718 mpFS->endElementNS(XML_p, XML_spTgt);
719 mpFS->endElementNS(XML_p, XML_tgtEl);
722 void PPTXAnimationExport::WriteAnimationCondList(const Any& rAny, sal_Int32 nToken)
724 if (!rAny.hasValue())
725 return;
727 std::vector<Cond> aList;
729 bool bIsMainSeqChild = isMainSeqChild();
731 Sequence<Any> aCondSeq;
732 if (rAny >>= aCondSeq)
734 for (int i = 0; i < aCondSeq.getLength(); i++)
736 Cond aCond(aCondSeq[i], bIsMainSeqChild);
737 if (aCond.isValid())
738 aList.push_back(aCond);
741 else
743 Cond aCond(rAny, bIsMainSeqChild);
744 if (aCond.isValid())
745 aList.push_back(aCond);
748 if (aList.size() > 0)
750 mpFS->startElementNS(XML_p, nToken);
752 for (const Cond& rCond : aList)
753 WriteAnimationCond(rCond);
755 mpFS->endElementNS(XML_p, nToken);
759 void PPTXAnimationExport::WriteAnimationCond(const Cond& rCond)
761 sal_Int32 nId = -1;
762 if (rCond.mpEvent)
764 if (rCond.mxShape.is())
766 mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
767 rCond.mpEvent);
768 WriteAnimationTarget(makeAny(rCond.mxShape));
769 mpFS->endElementNS(XML_p, XML_cond);
771 else if (rCond.mxNode.is() && (nId = GetAnimationNodeId(rCond.mxNode)) != -1)
773 mpFS->startElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
774 rCond.mpEvent);
775 mpFS->singleElementNS(XML_p, XML_tn, XML_val, OString::number(nId));
776 mpFS->endElementNS(XML_p, XML_cond);
778 else
780 mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay(), XML_evt,
781 rCond.mpEvent);
784 else
785 mpFS->singleElementNS(XML_p, XML_cond, XML_delay, rCond.getDelay());
788 void PPTXAnimationExport::WriteAnimationNodeAnimate(sal_Int32 nXmlNodeType)
790 const Reference<XAnimationNode>& rXNode = getCurrentNode();
791 Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
792 if (!rXAnimate.is())
793 return;
795 const char* pCalcMode = nullptr;
796 const char* pValueType = nullptr;
797 bool bSimple = (nXmlNodeType != XML_anim);
798 bool bTo = true;
800 if (!bSimple)
802 switch (rXAnimate->getCalcMode())
804 case AnimationCalcMode::DISCRETE:
805 pCalcMode = "discrete";
806 break;
807 case AnimationCalcMode::LINEAR:
808 pCalcMode = "lin";
809 break;
812 switch (AnimationExporter::GetValueTypeForAttributeName(rXAnimate->getAttributeName()))
814 case AnimationValueType::STRING:
815 pValueType = "str";
816 break;
817 case AnimationValueType::NUMBER:
818 pValueType = "num";
819 break;
820 case AnimationValueType::COLOR:
821 pValueType = "clr";
822 break;
826 if (nXmlNodeType == XML_animMotion)
828 OUString aPath;
829 Reference<XAnimateMotion> xMotion(rXNode, UNO_QUERY);
830 if (xMotion.is())
832 xMotion->getPath() >>= aPath;
833 ::basegfx::B2DPolyPolygon aPolyPoly;
834 if (::basegfx::utils::importFromSvgD(aPolyPoly, aPath, true, nullptr))
835 aPath = ::basegfx::utils::exportToSvgD(aPolyPoly, false, false, true, true);
838 mpFS->startElementNS(XML_p, nXmlNodeType, XML_origin, "layout", XML_path, aPath.toUtf8());
840 else if (nXmlNodeType == XML_animRot)
842 // when const char* is nullptr, the attribute is completely omitted in the output
843 const char* pBy = nullptr;
844 const char* pFrom = nullptr;
845 const char* pTo = nullptr;
846 OString aBy, aFrom, aTo;
848 Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
849 if (xTransform.is())
851 double value;
852 if (xTransform->getBy() >>= value)
854 aBy = OString::number(static_cast<int>(value * PER_DEGREE));
855 pBy = aBy.getStr();
858 if (xTransform->getFrom() >>= value)
860 aFrom = OString::number(static_cast<int>(value * PER_DEGREE));
861 pFrom = aFrom.getStr();
864 if (xTransform->getTo() >>= value)
866 aTo = OString::number(static_cast<int>(value * PER_DEGREE));
867 pTo = aTo.getStr();
871 mpFS->startElementNS(XML_p, nXmlNodeType, XML_by, pBy, XML_from, pFrom, XML_to, pTo);
873 else if (nXmlNodeType == XML_animClr)
875 Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
876 const char* pColorSpace = "rgb";
877 const char* pDirection = nullptr;
878 if (xColor.is() && xColor->getColorInterpolation() == AnimationColorSpace::HSL)
880 // Note: from, to, by can still be specified in any supported format.
881 pColorSpace = "hsl";
882 pDirection = xColor->getDirection() ? "cw" : "ccw";
884 mpFS->startElementNS(XML_p, nXmlNodeType, XML_clrSpc, pColorSpace, XML_dir, pDirection,
885 XML_calcmode, pCalcMode, XML_valueType, pValueType);
887 else
889 OUString sFrom, sTo, sBy;
890 if (rXAnimate.is() && nXmlNodeType == XML_anim)
892 OUString sAttributeName = rXAnimate->getAttributeName();
893 Any aFrom
894 = AnimationExporter::convertAnimateValue(rXAnimate->getFrom(), sAttributeName);
895 aFrom >>= sFrom;
896 Any aTo = AnimationExporter::convertAnimateValue(rXAnimate->getTo(), sAttributeName);
897 aTo >>= sTo;
898 Any aBy = AnimationExporter::convertAnimateValue(rXAnimate->getBy(), sAttributeName);
899 aBy >>= sBy;
902 mpFS->startElementNS(XML_p, nXmlNodeType, XML_calcmode, pCalcMode, XML_valueType,
903 pValueType, XML_from,
904 sFrom.isEmpty() ? nullptr : sFrom.toUtf8().getStr(), XML_to,
905 sTo.isEmpty() ? nullptr : sTo.toUtf8().getStr(), XML_by,
906 sBy.isEmpty() ? nullptr : sBy.toUtf8().getStr());
907 bTo = sTo.isEmpty() && sFrom.isEmpty() && sBy.isEmpty();
910 WriteAnimationNodeAnimateInside(bSimple, bTo);
911 mpFS->endElementNS(XML_p, nXmlNodeType);
914 void PPTXAnimationExport::WriteAnimationNodeAnimateInside(bool bSimple, bool bWriteTo)
916 const Reference<XAnimationNode>& rXNode = getCurrentNode();
917 Reference<XAnimate> rXAnimate(rXNode, UNO_QUERY);
918 if (!rXAnimate.is())
919 return;
921 const char* pAdditive = nullptr;
923 if (!bSimple)
925 switch (rXAnimate->getAdditive())
927 case AnimationAdditiveMode::BASE:
928 pAdditive = "base";
929 break;
930 case AnimationAdditiveMode::SUM:
931 pAdditive = "sum";
932 break;
933 case AnimationAdditiveMode::REPLACE:
934 pAdditive = "repl";
935 break;
936 case AnimationAdditiveMode::MULTIPLY:
937 pAdditive = "mult";
938 break;
939 case AnimationAdditiveMode::NONE:
940 pAdditive = "none";
941 break;
945 mpFS->startElementNS(XML_p, XML_cBhvr, XML_additive, pAdditive);
946 WriteAnimationNodeCommonPropsStart();
948 Reference<XIterateContainer> xIterate(rXNode->getParent(), UNO_QUERY);
949 WriteAnimationTarget(xIterate.is() ? xIterate->getTarget() : rXAnimate->getTarget());
951 Reference<XAnimateTransform> xTransform(rXNode, UNO_QUERY);
953 // The attribute name of AnimateTransform is "Transform", we have to fix it.
954 OUString sNewAttr;
955 if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::ROTATE)
956 sNewAttr = "Rotate";
958 WriteAnimationAttributeName(mpFS, xTransform.is() ? sNewAttr : rXAnimate->getAttributeName());
960 mpFS->endElementNS(XML_p, XML_cBhvr);
961 WriteAnimateValues(mpFS, rXAnimate);
963 Reference<XAnimateColor> xColor(rXNode, UNO_QUERY);
965 if (xColor.is())
967 WriteAnimateColorColor(mpFS, xColor->getBy(), XML_by);
968 WriteAnimateColorColor(mpFS, xColor->getFrom(), XML_from);
969 WriteAnimateColorColor(mpFS, xColor->getTo(), XML_to);
971 else if (xTransform.is() && xTransform->getTransformType() == AnimationTransformType::SCALE)
973 WriteAnimationProperty(mpFS, rXAnimate->getBy(), XML_by);
974 WriteAnimationProperty(mpFS, rXAnimate->getFrom(), XML_from);
975 WriteAnimationProperty(mpFS, rXAnimate->getTo(), XML_to);
977 else if (bWriteTo)
978 WriteAnimateTo(mpFS, rXAnimate->getTo(), rXAnimate->getAttributeName());
981 void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
983 const Reference<XAnimationNode>& rXNode = getCurrentNode();
984 const char* pDuration = nullptr;
985 const char* pRestart = nullptr;
986 const char* pNodeType = nullptr;
987 const char* pPresetClass = nullptr;
988 const char* pFill = nullptr;
989 double fDuration = 0;
990 Any aAny;
991 assert(mpContext);
993 aAny = rXNode->getDuration();
994 if (aAny.hasValue())
996 Timing eTiming;
998 if (aAny >>= eTiming)
1000 if (eTiming == Timing_INDEFINITE)
1001 pDuration = "indefinite";
1003 else
1004 aAny >>= fDuration;
1007 pRestart = convertAnimationRestart(rXNode->getRestart());
1009 sal_Int16 nType = mpContext->getEffectNodeType();
1010 if (nType != -1)
1012 pNodeType = convertEffectNodeType(nType);
1013 if (nType == EffectNodeType::TIMING_ROOT)
1015 if (!pDuration)
1016 pDuration = "indefinite";
1017 if (!pRestart)
1018 pRestart = "never";
1020 else if (nType == EffectNodeType::MAIN_SEQUENCE)
1022 pDuration = "indefinite";
1026 sal_uInt32 nPresetClass = mpContext->getEffectPresetClass();
1027 if (nPresetClass != DFF_ANIM_PRESS_CLASS_USER_DEFINED)
1028 pPresetClass = convertEffectPresetClass(nPresetClass);
1030 sal_uInt32 nPresetId = 0;
1031 bool bPresetId = false;
1032 const OUString& rPresetId = mpContext->getEffectPresetId();
1033 if (rPresetId.getLength() > 0)
1035 nPresetId = AnimationExporter::GetPresetID(rPresetId, nPresetClass, bPresetId);
1036 bPresetId = true;
1039 sal_uInt32 nPresetSubType = 0;
1040 bool bPresetSubType = false;
1041 const OUString& sPresetSubType = mpContext->getEffectPresetSubType();
1042 if (sPresetSubType.getLength() > 0)
1044 nPresetSubType
1045 = AnimationExporter::TranslatePresetSubType(nPresetClass, nPresetId, sPresetSubType);
1046 bPresetSubType = true;
1049 if (nType != EffectNodeType::TIMING_ROOT && nType != EffectNodeType::MAIN_SEQUENCE)
1051 // it doesn't seem to work right on root and mainseq nodes
1052 sal_Int16 nFill = AnimationExporter::GetFillMode(rXNode, AnimationFill::AUTO);
1053 pFill = convertAnimationFill(nFill);
1056 bool bAutoReverse = rXNode->getAutoReverse();
1058 mpFS->startElementNS(
1059 XML_p, XML_cTn, XML_id, OString::number(GetNextAnimationNodeId(rXNode)), XML_dur,
1060 fDuration != 0 ? OString::number(static_cast<sal_Int32>(fDuration * 1000.0)).getStr()
1061 : pDuration,
1062 XML_autoRev, bAutoReverse ? "1" : nullptr, XML_restart, pRestart, XML_nodeType, pNodeType,
1063 XML_fill, pFill, XML_presetClass, pPresetClass, XML_presetID,
1064 bPresetId ? OString::number(nPresetId).getStr() : nullptr, XML_presetSubtype,
1065 bPresetSubType ? OString::number(nPresetSubType).getStr() : nullptr);
1067 WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
1068 WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
1070 if (rXNode->getType() == AnimationNodeType::ITERATE)
1072 Reference<XIterateContainer> xIterate(rXNode, UNO_QUERY);
1073 if (xIterate.is())
1075 const char* sType = convertTextAnimationType(xIterate->getIterateType());
1077 mpFS->startElementNS(XML_p, XML_iterate, XML_type, sType);
1078 mpFS->singleElementNS(XML_p, XML_tmAbs, XML_val,
1079 OString::number(xIterate->getIterateInterval() * 1000));
1080 mpFS->endElementNS(XML_p, XML_iterate);
1084 const std::vector<NodeContextPtr>& aChildNodes = mpContext->getChildNodes();
1085 if (!aChildNodes.empty())
1087 mpFS->startElementNS(XML_p, XML_childTnLst);
1088 for (const NodeContextPtr& pChildContext : aChildNodes)
1090 if (pChildContext->isValid())
1091 WriteAnimationNode(pChildContext);
1093 mpFS->endElementNS(XML_p, XML_childTnLst);
1095 mpFS->endElementNS(XML_p, XML_cTn);
1098 void PPTXAnimationExport::WriteAnimationNodeSeq()
1100 SAL_INFO("sd.eppt", "write animation node SEQ");
1102 mpFS->startElementNS(XML_p, XML_seq);
1104 WriteAnimationNodeCommonPropsStart();
1106 WriteAnimationCondListForSeq(mpFS, XML_prevCondLst);
1107 WriteAnimationCondListForSeq(mpFS, XML_nextCondLst);
1109 mpFS->endElementNS(XML_p, XML_seq);
1112 void PPTXAnimationExport::WriteAnimationNodeEffect()
1114 SAL_INFO("sd.eppt", "write animation node FILTER");
1115 Reference<XTransitionFilter> xFilter(getCurrentNode(), UNO_QUERY);
1116 if (xFilter.is())
1118 const char* pFilter = ::ppt::AnimationExporter::FindTransitionName(
1119 xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection());
1120 const char* pMode = xFilter->getMode() ? "in" : "out";
1121 mpFS->startElementNS(XML_p, XML_animEffect, XML_filter, pFilter, XML_transition, pMode);
1123 WriteAnimationNodeAnimateInside(false);
1125 mpFS->endElementNS(XML_p, XML_animEffect);
1129 void PPTXAnimationExport::WriteAnimationNodeCommand()
1131 SAL_INFO("sd.eppt", "write animation node COMMAND");
1132 Reference<XCommand> xCommand(getCurrentNode(), UNO_QUERY);
1133 if (!xCommand.is())
1134 return;
1136 const char* pType = "call";
1137 const char* pCommand = nullptr;
1138 switch (xCommand->getCommand())
1140 case EffectCommands::VERB:
1141 pType = "verb";
1142 pCommand = "1"; /* FIXME hardcoded viewing */
1143 break;
1144 case EffectCommands::PLAY:
1145 pCommand = "play";
1146 break;
1147 case EffectCommands::TOGGLEPAUSE:
1148 pCommand = "togglePause";
1149 break;
1150 case EffectCommands::STOP:
1151 pCommand = "stop";
1152 break;
1153 default:
1154 SAL_WARN("sd.eppt", "unknown command: " << xCommand->getCommand());
1155 break;
1158 mpFS->startElementNS(XML_p, XML_cmd, XML_type, pType, XML_cmd, pCommand);
1160 WriteAnimationNodeAnimateInside(false);
1161 mpFS->startElementNS(XML_p, XML_cBhvr);
1162 WriteAnimationNodeCommonPropsStart();
1163 WriteAnimationTarget(xCommand->getTarget());
1164 mpFS->endElementNS(XML_p, XML_cBhvr);
1166 mpFS->endElementNS(XML_p, XML_cmd);
1169 void PPTXAnimationExport::WriteAnimationNodeAudio()
1171 SAL_INFO("sd.eppt", "write animation node audio");
1172 Reference<XAudio> xAudio(getCurrentNode(), UNO_QUERY);
1174 OUString sUrl;
1175 OUString sRelId;
1176 OUString sName;
1178 if (!(xAudio.is() && (xAudio->getSource() >>= sUrl) && !sUrl.isEmpty()
1179 && sUrl.endsWithIgnoreAsciiCase(".wav")))
1180 return;
1182 mrPowerPointExport.embedEffectAudio(mpFS, sUrl, sRelId, sName);
1184 mpFS->startElementNS(XML_p, XML_audio);
1185 mpFS->startElementNS(XML_p, XML_cMediaNode);
1187 mpFS->startElementNS(XML_p, XML_cTn);
1188 WriteAnimationCondList(mpContext->getCondition(true), XML_stCondLst);
1189 WriteAnimationCondList(mpContext->getCondition(false), XML_endCondLst);
1190 mpFS->endElementNS(XML_p, XML_cTn);
1192 mpFS->startElementNS(XML_p, XML_tgtEl);
1193 mpFS->singleElementNS(XML_p, XML_sndTgt, FSNS(XML_r, XML_embed),
1194 sRelId.isEmpty() ? nullptr : sRelId.toUtf8().getStr(), XML_name,
1195 sUrl.isEmpty() ? nullptr : sName.toUtf8().getStr());
1196 mpFS->endElementNS(XML_p, XML_tgtEl);
1198 mpFS->endElementNS(XML_p, XML_cMediaNode);
1199 mpFS->endElementNS(XML_p, XML_audio);
1202 void PPTXAnimationExport::WriteAnimationNode(const NodeContextPtr& pContext)
1204 const NodeContext* pSavedContext = mpContext;
1205 mpContext = pContext.get();
1207 const Reference<XAnimationNode>& rXNode = getCurrentNode();
1209 SAL_INFO("sd.eppt", "export node type: " << rXNode->getType());
1210 sal_Int32 xmlNodeType = extractNodeType(rXNode);
1212 switch (xmlNodeType)
1214 case XML_par:
1215 mpFS->startElementNS(XML_p, xmlNodeType);
1216 WriteAnimationNodeCommonPropsStart();
1217 mpFS->endElementNS(XML_p, xmlNodeType);
1218 break;
1219 case XML_seq:
1220 WriteAnimationNodeSeq();
1221 break;
1222 case XML_animScale:
1223 case XML_animRot:
1224 case XML_anim:
1225 case XML_animMotion:
1226 case XML_animClr:
1227 case XML_set:
1228 WriteAnimationNodeAnimate(xmlNodeType);
1229 break;
1230 case XML_animEffect:
1231 WriteAnimationNodeEffect();
1232 break;
1233 case XML_cmd:
1234 WriteAnimationNodeCommand();
1235 break;
1236 case XML_audio:
1237 WriteAnimationNodeAudio();
1238 break;
1239 default:
1240 SAL_WARN("sd.eppt", "export ooxml node type: " << xmlNodeType);
1241 break;
1244 mpContext = pSavedContext;
1247 void PPTXAnimationExport::WriteAnimations(const Reference<XDrawPage>& rXDrawPage)
1249 Reference<XAnimationNodeSupplier> xNodeSupplier(rXDrawPage, UNO_QUERY);
1250 if (!xNodeSupplier.is())
1251 return;
1253 const Reference<XAnimationNode> xNode(xNodeSupplier->getAnimationNode());
1254 if (!xNode.is())
1255 return;
1257 Reference<XEnumerationAccess> xEnumerationAccess(xNode, UNO_QUERY);
1258 if (!xEnumerationAccess.is())
1259 return;
1261 Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(), UNO_QUERY);
1262 if (!(xEnumeration.is() && xEnumeration->hasMoreElements()))
1263 return;
1265 auto pNodeContext = std::make_unique<NodeContext>(xNode, false, false);
1266 if (pNodeContext->isValid())
1268 mpFS->startElementNS(XML_p, XML_timing);
1269 mpFS->startElementNS(XML_p, XML_tnLst);
1271 WriteAnimationNode(pNodeContext);
1273 mpFS->endElementNS(XML_p, XML_tnLst);
1274 mpFS->endElementNS(XML_p, XML_timing);
1278 sal_Int32 PPTXAnimationExport::GetNextAnimationNodeId(const Reference<XAnimationNode>& xNode)
1280 sal_Int32 nId = mrPowerPointExport.GetNextAnimationNodeID();
1281 maAnimationNodeIdMap[xNode] = nId;
1282 return nId;
1285 sal_Int32 PPTXAnimationExport::GetAnimationNodeId(const Reference<XAnimationNode>& xNode)
1287 sal_Int32 nId = -1;
1288 const auto& aIter = maAnimationNodeIdMap.find(xNode);
1289 if (aIter != maAnimationNodeIdMap.end())
1291 nId = aIter->second;
1293 return nId;
1296 NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
1297 bool bIsIterateChild)
1298 : mxNode(xNode)
1299 , mbMainSeqChild(bMainSeqChild)
1300 , mbValid(true)
1301 , mnEffectNodeType(-1)
1302 , mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED)
1304 assert(xNode.is());
1306 initUserData();
1308 initValid(initChildNodes(), bIsIterateChild);
1311 void NodeContext::initUserData()
1313 assert(mxNode.is());
1315 Sequence<NamedValue> aUserData = mxNode->getUserData();
1316 const Any* aIndexedData[DFF_ANIM_PROPERTY_ID_COUNT];
1317 AnimationExporter::GetUserData(aUserData, aIndexedData, sizeof(aIndexedData));
1319 const Any* pAny = aIndexedData[DFF_ANIM_NODE_TYPE];
1320 if (pAny)
1321 *pAny >>= mnEffectNodeType;
1323 pAny = aIndexedData[DFF_ANIM_PRESET_CLASS];
1324 if (pAny)
1325 *pAny >>= mnEffectPresetClass;
1327 pAny = aIndexedData[DFF_ANIM_PRESET_ID];
1328 if (pAny)
1329 *pAny >>= msEffectPresetId;
1331 pAny = aIndexedData[DFF_ANIM_PRESET_SUB_TYPE];
1332 if (pAny)
1333 *pAny >>= msEffectPresetSubType;
1336 void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
1338 sal_Int16 nType = mxNode->getType();
1340 if (nType == AnimationNodeType::ITERATE)
1342 Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
1343 mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
1344 && !maChildNodes.empty();
1346 else if (nType == AnimationNodeType::COMMAND)
1348 Reference<XCommand> xCommand(mxNode, UNO_QUERY);
1349 mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
1351 else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
1353 mbValid = bHasValidChild;
1355 else if (nType == AnimationNodeType::AUDIO)
1357 Reference<XAudio> xAudio(mxNode, UNO_QUERY);
1358 OUString sURL;
1359 mbValid
1360 = xAudio.is() && (xAudio->getSource() >>= sURL) && sURL.endsWithIgnoreAsciiCase(".wav");
1362 else
1364 Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
1365 mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
1369 bool NodeContext::initChildNodes()
1371 bool bValid = false;
1372 Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
1373 if (xEnumerationAccess.is())
1375 Reference<XEnumeration> xEnumeration(xEnumerationAccess->createEnumeration(), UNO_QUERY);
1376 bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
1377 bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
1378 if (xEnumeration.is())
1380 while (xEnumeration->hasMoreElements())
1382 Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
1383 if (xChildNode.is())
1385 auto pChildContext
1386 = std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
1387 if (pChildContext->isValid())
1388 bValid = true;
1389 maChildNodes.push_back(std::move(pChildContext));
1394 return bValid;
1397 Any NodeContext::getCondition(bool bBegin) const
1399 const bool bParent
1400 = (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
1401 const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
1403 return bBegin ? rNode->getBegin() : rNode->getEnd();
1406 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */