summaryrefslogtreecommitdiffstats
path: root/sd/source/filter/ppt/pptinanimations.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sd/source/filter/ppt/pptinanimations.cxx')
-rw-r--r--sd/source/filter/ppt/pptinanimations.cxx3294
1 files changed, 3294 insertions, 0 deletions
diff --git a/sd/source/filter/ppt/pptinanimations.cxx b/sd/source/filter/ppt/pptinanimations.cxx
new file mode 100644
index 000000000..ff49054dd
--- /dev/null
+++ b/sd/source/filter/ppt/pptinanimations.cxx
@@ -0,0 +1,3294 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/animations/XAnimationNodeSupplier.hpp>
+#include <com/sun/star/animations/AnimationFill.hpp>
+#include <com/sun/star/animations/AnimationRestart.hpp>
+#include <com/sun/star/animations/Timing.hpp>
+#include <com/sun/star/animations/Event.hpp>
+#include <com/sun/star/animations/AnimationEndSync.hpp>
+#include <com/sun/star/animations/Command.hpp>
+#include <com/sun/star/animations/EventTrigger.hpp>
+#include <com/sun/star/animations/AnimationNodeType.hpp>
+#include <com/sun/star/animations/AnimationTransformType.hpp>
+#include <com/sun/star/animations/AnimationCalcMode.hpp>
+#include <com/sun/star/animations/AnimationValueType.hpp>
+#include <com/sun/star/animations/AnimationAdditiveMode.hpp>
+#include <com/sun/star/animations/XIterateContainer.hpp>
+#include <com/sun/star/animations/XAnimateSet.hpp>
+#include <com/sun/star/animations/XAnimationNode.hpp>
+#include <com/sun/star/animations/XAudio.hpp>
+#include <com/sun/star/animations/XCommand.hpp>
+#include <com/sun/star/animations/XTransitionFilter.hpp>
+#include <com/sun/star/animations/XAnimateColor.hpp>
+#include <com/sun/star/animations/XAnimateMotion.hpp>
+#include <com/sun/star/animations/XAnimateTransform.hpp>
+#include <com/sun/star/animations/ValuePair.hpp>
+#include <com/sun/star/animations/AnimationColorSpace.hpp>
+#include <com/sun/star/presentation/EffectNodeType.hpp>
+#include <com/sun/star/presentation/EffectPresetClass.hpp>
+#include <com/sun/star/presentation/ShapeAnimationSubType.hpp>
+#include <com/sun/star/presentation/EffectCommands.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/drawing/XDrawPage.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/presentation/ParagraphTarget.hpp>
+#include <com/sun/star/presentation/TextAnimationType.hpp>
+#include <comphelper/processfactory.hxx>
+#include <oox/helper/addtosequence.hxx>
+#include <oox/ppt/pptfilterhelpers.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+#include <tools/debug.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+#include <svx/svdotext.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <animations.hxx>
+#include "pptanimations.hxx"
+#include "pptinanimations.hxx"
+#include "pptatom.hxx"
+#include "pptin.hxx"
+#include <randomnode.hxx>
+
+#include <algorithm>
+#include <memory>
+
+using ::com::sun::star::beans::NamedValue;
+using ::com::sun::star::container::XEnumerationAccess;
+using ::com::sun::star::container::XEnumeration;
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::animations;
+using namespace ::com::sun::star::presentation;
+
+namespace ppt
+{
+
+static SvStream& operator>>(SvStream& rIn, AnimationNode& rNode )
+{
+ rIn.ReadInt32( rNode.mnU1 );
+ rIn.ReadInt32( rNode.mnRestart );
+ rIn.ReadInt32( rNode.mnGroupType );
+ rIn.ReadInt32( rNode.mnFill );
+ rIn.ReadInt32( rNode.mnU3 );
+ rIn.ReadInt32( rNode.mnU4 );
+ rIn.ReadInt32( rNode.mnDuration );
+ rIn.ReadInt32( rNode.mnNodeType );
+
+ return rIn;
+}
+
+bool PropertySet::hasProperty( sal_Int32 nProperty ) const
+{
+ return maProperties.find( nProperty ) != maProperties.end();
+}
+
+Any PropertySet::getProperty( sal_Int32 nProperty ) const
+{
+ PropertySetMap_t::const_iterator aIter( maProperties.find( nProperty ) );
+ if( aIter != maProperties.end() )
+ return (*aIter).second;
+ else
+ return Any();
+}
+
+AnimationImporter::AnimationImporter( ImplSdPPTImport* pPPTImport, SvStream& rStCtrl )
+: mpPPTImport( pPPTImport ), mrStCtrl( rStCtrl )
+{
+}
+
+int AnimationImporter::import( const Reference< XDrawPage >& xPage, const DffRecordHeader& rProgTagContentHd )
+{
+ int nNodes = 0;
+
+#ifdef DBG_ANIM_LOG
+ static int ppt_anim_debug_stream_number = 1;
+ OUString ppt_anim_debug_filename("ppt-animation-import-debug-output-");
+ ppt_anim_debug_filename += OUString::number(ppt_anim_debug_stream_number++);
+ ppt_anim_debug_filename += ".xml";
+ mpFile = fopen( OUStringToOString( ppt_anim_debug_filename, RTL_TEXTENCODING_UTF8).getStr() , "w+" );
+#endif
+ dump("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+
+ Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY );
+ if( xNodeSupplier.is() )
+ {
+ mxRootNode = xNodeSupplier->getAnimationNode();
+ if( mxRootNode.is() )
+ {
+ Reference< XAnimationNode > xParent;
+
+ std::unique_ptr<Atom> pAtom(Atom::import( rProgTagContentHd, mrStCtrl ));
+ if( pAtom )
+ {
+ nNodes = importAnimationContainer( pAtom.get(), xParent );
+ }
+
+ std::for_each( maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
+ sd::stl_process_after_effect_node_func );
+ }
+ }
+
+#ifdef DBG_ANIM_LOG
+ fclose( mpFile );
+#endif
+
+ return nNodes;
+}
+
+Reference< XAnimationNode > AnimationImporter::createNode( const Atom* pAtom, const AnimationNode& rNode )
+{
+ const char* pServiceName = nullptr;
+
+ switch( rNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimIteration ) )
+ pServiceName = "com.sun.star.animations.IterateContainer";
+ else
+ pServiceName = "com.sun.star.animations.ParallelTimeContainer";
+ break;
+ case mso_Anim_GroupType_SEQ:
+ pServiceName = "com.sun.star.animations.SequenceTimeContainer";
+ break;
+ case mso_Anim_GroupType_NODE:
+ {
+ switch( rNode.mnNodeType )
+ {
+ case mso_Anim_Behaviour_FILTER:
+ case mso_Anim_Behaviour_ANIMATION:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ pServiceName = "com.sun.star.animations.AnimateSet";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ pServiceName = "com.sun.star.animations.AnimateColor";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ pServiceName = "com.sun.star.animations.AnimateTransform";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ pServiceName = "com.sun.star.animations.AnimateTransform";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ pServiceName = "com.sun.star.animations.AnimateMotion";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateFilter ) )
+ pServiceName = "com.sun.star.animations.TransitionFilter";
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ pServiceName = "com.sun.star.animations.Command";
+ else
+ pServiceName = "com.sun.star.animations.Animate";
+ break;
+ }
+ break;
+ }
+ case mso_Anim_GroupType_MEDIA:
+ pServiceName = "com.sun.star.animations.Audio";
+ break;
+
+ default:
+ pServiceName = "com.sun.star.animations.Animate";
+ break;
+ }
+
+ Reference< XAnimationNode > xNode;
+ if( pServiceName )
+ {
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ const OUString aServiceName( OUString::createFromAscii(pServiceName) );
+ Reference< XInterface > xFac( xContext->getServiceManager()->createInstanceWithContext(aServiceName, xContext) );
+ xNode.set(xFac , UNO_QUERY );
+ }
+
+ DBG_ASSERT( xNode.is(), "sd::AnimationImporter::createNode(), node creation failed!" );
+ return xNode;
+}
+
+static bool is_random( const AnimationNode& rNode, const PropertySet& rSet, sal_Int32& rPresetClass )
+{
+ if( rNode.mnGroupType != mso_Anim_GroupType_PAR )
+ return false;
+
+ if( !rSet.hasProperty( DFF_ANIM_PRESET_ID ) || !rSet.hasProperty( DFF_ANIM_PRESET_CLASS ) )
+ return false;
+
+ sal_Int32 nPresetId = 0;
+ if( !(rSet.getProperty( DFF_ANIM_PRESET_ID ) >>= nPresetId) || (nPresetId != 24) )
+ return false;
+
+ sal_Int32 nPresetClass = 0;
+ if( !(rSet.getProperty( DFF_ANIM_PRESET_CLASS ) >>= nPresetClass) )
+ return false;
+
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: rPresetClass = EffectPresetClass::ENTRANCE; return true;
+ case DFF_ANIM_PRESS_CLASS_EXIT: rPresetClass = EffectPresetClass::EXIT; return true;
+ }
+ return false;
+}
+
+int AnimationImporter::importAnimationContainer( const Atom* pAtom, const Reference< XAnimationNode >& xParent )
+{
+ int nNodes = 0;
+ if( pAtom->seekToContent() )
+ {
+ AnimationNode aNode;
+ const Atom* pAnimationNodeAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimNode );
+ if( pAnimationNodeAtom && pAnimationNodeAtom->seekToContent() )
+ mrStCtrl >> aNode;
+
+ PropertySet aSet;
+ const Atom* pAnimationPropertySetAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimPropertySet );
+ if( pAnimationPropertySetAtom )
+ importPropertySetContainer( pAnimationPropertySetAtom, aSet );
+
+ Reference< XAnimationNode > xNode;
+
+ if( xParent.is() )
+ {
+ sal_Int32 nPresetClass;
+ if( is_random( aNode, aSet, nPresetClass ) )
+ {
+ // create a random animation node with the given preset class
+ xNode.set( sd::RandomAnimationNode_createInstance( static_cast<sal_Int16>(nPresetClass) ), UNO_QUERY );
+ }
+
+ if( !xNode.is() )
+ {
+ // create a node for the given atom
+ xNode = createNode( pAtom, aNode );
+ }
+ }
+ else
+ {
+ // if we have no parent we fill the root node
+ xNode = mxRootNode;
+ }
+
+ // import if we have a node and it's not random
+ if( xNode.is() )
+ {
+ fillNode( xNode, aNode, aSet );
+
+ switch( aNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ {
+ dump( "<par" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importTimeContainer( pAtom, xNode );
+ dump( "</par>\n" );
+
+ // for iteration containers, map target from children to iteration
+ Reference< XIterateContainer > xIter( xNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ double fDuration = 0.0;
+ Any aTarget, aEmpty;
+ Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
+ if( xEnumerationAccess.is() )
+ {
+ Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
+ if( xEnumeration.is() )
+ {
+ while( xEnumeration->hasMoreElements() )
+ {
+ Reference< XAnimate > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
+ if( xChildNode.is() )
+ {
+ double fChildBegin = 0.0;
+ double fChildDuration = 0.0;
+ xChildNode->getBegin() >>= fChildBegin;
+ xChildNode->getDuration() >>= fChildDuration;
+
+ fChildDuration += fChildBegin;
+ if( fChildDuration > fDuration )
+ fDuration = fChildDuration;
+
+ if( !aTarget.hasValue() )
+ aTarget = xChildNode->getTarget();
+
+ xChildNode->setTarget( aEmpty );
+ }
+ }
+ }
+ }
+
+ xIter->setTarget( aTarget );
+
+ double fIterateInterval = xIter->getIterateInterval() * fDuration / 100;
+ xIter->setIterateInterval( fIterateInterval );
+ }
+ }
+ break;
+
+ case mso_Anim_GroupType_SEQ:
+ {
+ dump( "<seq" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importTimeContainer( pAtom, xNode );
+ dump( "</seq>\n" );
+
+ if( aSet.hasProperty( DFF_ANIM_NODE_TYPE ) )
+ {
+ sal_Int32 nPPTNodeType = 0;
+ if( aSet.getProperty( DFF_ANIM_NODE_TYPE ) >>= nPPTNodeType )
+ {
+ switch(nPPTNodeType)
+ {
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE:
+ oox::ppt::fixMainSequenceTiming( xNode );
+ break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:
+ oox::ppt::fixInteractiveSequenceTiming( xNode );
+ break;
+ }
+ }
+ }
+ }
+ break;
+
+ case mso_Anim_GroupType_NODE:
+ {
+#ifdef DBG_ANIM_LOG
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ {
+ dump( "<set" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ {
+ dump( "<animateColor" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ {
+ dump( "<animateScale" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ {
+ dump( "<animateRotation" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ {
+ dump( "<animateMotion" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimate ) )
+ {
+ dump( "<animate" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateFilter ) )
+ {
+ dump( "<animateFilter" );
+ }
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ {
+ dump( "<command" );
+ }
+ else
+ {
+ OSL_FAIL( "unknown node atom!" );
+ dump_atom_header( pAtom, true, false );
+ dump_atom( pAtom );
+ dump_atom_header( pAtom, false, false );
+ break;
+ }
+ dump( aNode );
+ dump( aSet );
+#endif
+ int nANCNodes = importAnimationNodeContainer( pAtom, xNode );
+ if( !convertAnimationNode( xNode, xParent ) )
+ xNode = nullptr;
+ else
+ nNodes += nANCNodes;
+ dump( "/>\n");
+
+ }
+ break;
+
+ case mso_Anim_GroupType_MEDIA:
+ {
+ dump( "<audio" );
+ dump( aNode );
+ dump( aSet );
+ nNodes += importAudioContainer( pAtom, xNode );
+ dump( "</audio>\n" );
+ }
+ break;
+
+ default:
+ OSL_FAIL( "unknown group atom!" );
+
+ dump_atom_header( pAtom, true, false );
+ dump_atom( pAtom );
+ dump_atom_header( pAtom, false, false );
+ break;
+
+ }
+ }
+
+ if( xParent.is() && xNode.is() )
+ {
+ Reference< XTimeContainer > xParentContainer( xParent, UNO_QUERY );
+ DBG_ASSERT( xParentContainer.is(), "parent is no container, then why do I have a child here?" );
+ if( xParentContainer.is() )
+ {
+ xParentContainer->appendChild( xNode );
+ }
+ }
+ }
+
+ return nNodes;
+}
+
+bool AnimationImporter::convertAnimationNode( const Reference< XAnimationNode >& xNode, const Reference< XAnimationNode >& xParent )
+{
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+ if( !xAnimate.is() )
+ return true;
+
+ if( !xAnimate->getTarget().hasValue() )
+ return false;
+
+ const sal_Int16 nNodeType = xNode->getType();
+
+ if( nNodeType == AnimationNodeType::TRANSITIONFILTER )
+ return true;
+
+ OUString aAttributeName( xAnimate->getAttributeName() );
+
+ if( (nNodeType == AnimationNodeType::SET) && aAttributeName == "fill.on" )
+ return false;
+
+ const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
+
+ oox::ppt::AnimationAttributeEnum eAttribute = oox::ppt::AnimationAttributeEnum::UNKNOWN;
+
+ if( (nNodeType == AnimationNodeType::ANIMATEMOTION) ||
+ (nNodeType == AnimationNodeType::ANIMATETRANSFORM) )
+ {
+ aAttributeName.clear();
+ }
+ else
+ {
+ while( p->mpMSName )
+ {
+ if( aAttributeName.equalsAscii( p->mpMSName ) )
+ break;
+
+ p++;
+ }
+
+ DBG_ASSERT( p->mpMSName || aAttributeName.isEmpty(), "sd::AnimationImporter::convertAnimationNode(), unknown attribute!" );
+#ifdef DBG_ANIM_LOG
+ if( p->mpMSName == 0 ) dump( "<error text=\"sd::AnimationImporter::convertAnimationNode(), unknown attribute!\"/>\n" );
+#endif
+
+ eAttribute = p->meAttribute;
+
+ if( p->mpAPIName )
+ aAttributeName = OUString::createFromAscii( p->mpAPIName );
+ }
+
+ xAnimate->setAttributeName( aAttributeName );
+
+ if(eAttribute != oox::ppt::AnimationAttributeEnum::UNKNOWN)
+ {
+ Any aAny( xAnimate->getFrom() );
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setFrom( aAny );
+ }
+
+ aAny = xAnimate->getBy();
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setBy( aAny );
+ }
+
+ aAny = xAnimate->getTo();
+ if( aAny.hasValue() )
+ {
+ if(oox::ppt::convertAnimationValue(eAttribute, aAny))
+ xAnimate->setTo( aAny );
+ }
+
+ Sequence< Any > aValues( xAnimate->getValues() );
+ if( aValues.hasElements() )
+ {
+ for( Any& rValue : asNonConstRange(aValues) )
+ oox::ppt::convertAnimationValue(eAttribute, rValue);
+
+ xAnimate->setValues( aValues );
+ }
+
+ OUString aFormula( xAnimate->getFormula() );
+ if( !aFormula.isEmpty() )
+ {
+ if(oox::ppt::convertMeasure(aFormula))
+ xAnimate->setFormula( aFormula );
+ }
+ }
+
+ // check for after-effect
+ Sequence< NamedValue > aUserData( xNode->getUserData() );
+ NamedValue* pLastValue = aUserData.getArray();
+ sal_Int32 nRemoved = 0;
+
+ bool bAfterEffect = false;
+ sal_Int32 nMasterRel = 0;
+ for( const NamedValue& rValue : std::as_const(aUserData) )
+ {
+ if ( rValue.Name == "after-effect" )
+ {
+ rValue.Value >>= bAfterEffect;
+ nRemoved++;
+ }
+ else if ( rValue.Name == "master-rel" )
+ {
+ rValue.Value >>= nMasterRel;
+ nRemoved++;
+ }
+ else
+ {
+ if( nRemoved )
+ *pLastValue = rValue;
+ pLastValue++;
+ }
+ }
+
+ if( nRemoved )
+ {
+ aUserData.realloc( aUserData.getLength() - nRemoved );
+ xNode->setUserData( aUserData );
+ }
+
+ // if it's an after effect node, add it to the list for
+ // later processing
+ // after effect nodes are not inserted at their import
+ // position, so return false in this case
+ if( bAfterEffect )
+ {
+ if( nMasterRel != 2 )
+ {
+ Event aEvent;
+
+ aEvent.Source <<= xParent;
+ aEvent.Trigger = EventTrigger::END_EVENT;
+ aEvent.Repeat = 0;
+
+ xNode->setBegin( Any( aEvent ) );
+ }
+
+ // add to after effect nodes for later processing
+ sd::AfterEffectNode aNode( xNode, xParent, nMasterRel == 2 );
+ maAfterEffectNodes.push_back( aNode );
+ return false;
+ }
+
+ return true;
+}
+
+void AnimationImporter::fillNode( Reference< XAnimationNode > const & xNode, const AnimationNode& rNode, const PropertySet& rSet )
+{
+ bool bAfterEffect = false;
+
+ // attribute Restart
+ if( rNode.mnRestart )
+ {
+ sal_Int16 nRestart = AnimationRestart::DEFAULT;
+ switch( rNode.mnRestart )
+ {
+ case 1: nRestart = AnimationRestart::ALWAYS; break;
+ case 2: nRestart = AnimationRestart::WHEN_NOT_ACTIVE; break;
+ case 3: nRestart = AnimationRestart::NEVER; break;
+ }
+ xNode->setRestart( nRestart );
+ }
+
+ // attribute Fill
+ if( rNode.mnFill )
+ {
+ sal_Int16 nFill = AnimationFill::DEFAULT;
+ switch( rNode.mnFill )
+ {
+ case 1: nFill = AnimationFill::REMOVE; break;
+ case 2: nFill = AnimationFill::FREEZE; break;
+ case 3: nFill = AnimationFill::HOLD; break;
+ case 4: nFill = AnimationFill::TRANSITION; break;
+ }
+ xNode->setFill( nFill );
+ }
+
+ // attribute Duration
+ if( rNode.mnDuration )
+ {
+ Any aDuration;
+ if( rNode.mnDuration > 0 )
+ {
+ aDuration <<= rNode.mnDuration / 1000.0;
+ }
+ else if( rNode.mnDuration < 0 )
+ {
+ aDuration <<= Timing_INDEFINITE;
+ }
+ xNode->setDuration( aDuration );
+ }
+
+ // TODO: DFF_ANIM_PATH_EDIT_MODE
+
+ // set user data
+ Sequence< NamedValue > aUserData;
+
+ // attribute Type
+ if( rSet.hasProperty( DFF_ANIM_NODE_TYPE ) )
+ {
+ sal_Int32 nPPTNodeType = 0;
+ if( rSet.getProperty( DFF_ANIM_NODE_TYPE ) >>= nPPTNodeType )
+ {
+ sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
+ switch( nPPTNodeType )
+ {
+ case DFF_ANIM_NODE_TYPE_CLICK_PARALLEL: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_ON_CLICK: nNodeType = css::presentation::EffectNodeType::ON_CLICK; break;
+ case DFF_ANIM_NODE_TYPE_WITH_GROUP: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_WITH_PREVIOUS: nNodeType = css::presentation::EffectNodeType::WITH_PREVIOUS; break;
+ case DFF_ANIM_NODE_TYPE_AFTER_GROUP: [[fallthrough]];
+ case DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS: nNodeType = css::presentation::EffectNodeType::AFTER_PREVIOUS; break;
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE: nNodeType = css::presentation::EffectNodeType::MAIN_SEQUENCE; break;
+ case DFF_ANIM_NODE_TYPE_TIMING_ROOT: nNodeType = css::presentation::EffectNodeType::TIMING_ROOT; break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:nNodeType = css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE; break;
+ }
+
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "node-type";
+ pUserData[nSize].Value <<= nNodeType;
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_GROUP_ID ) )
+ {
+ sal_Int32 nGroupId;
+ if( rSet.getProperty( DFF_ANIM_GROUP_ID ) >>= nGroupId )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "group-id";
+ pUserData[nSize].Value <<= nGroupId;
+ }
+ }
+
+ sal_Int16 nEffectPresetClass = EffectPresetClass::CUSTOM;
+ sal_Int32 nPresetId = 0;
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_CLASS ) )
+ {
+ sal_Int32 nPresetClass = 0;
+ if ( rSet.getProperty( DFF_ANIM_PRESET_CLASS ) >>= nPresetClass )
+ {
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: nEffectPresetClass = EffectPresetClass::ENTRANCE; break;
+ case DFF_ANIM_PRESS_CLASS_EXIT: nEffectPresetClass = EffectPresetClass::EXIT; break;
+ case DFF_ANIM_PRESS_CLASS_EMPHASIS: nEffectPresetClass = EffectPresetClass::EMPHASIS; break;
+ case DFF_ANIM_PRESS_CLASS_MOTIONPATH: nEffectPresetClass = EffectPresetClass::MOTIONPATH; break;
+ case DFF_ANIM_PRESS_CLASS_OLE_ACTION: nEffectPresetClass = EffectPresetClass::OLEACTION; break;
+ case DFF_ANIM_PRESS_CLASS_MEDIACALL: nEffectPresetClass = EffectPresetClass::MEDIACALL; break;
+ }
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-class";
+ pUserData[nSize].Value <<= nEffectPresetClass;
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_ID ) )
+ {
+ if( rSet.getProperty( DFF_ANIM_PRESET_ID ) >>= nPresetId )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-id";
+
+ const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
+ while( p->mpStrPresetId && ((p->mnPresetClass != nEffectPresetClass) || (p->mnPresetId != nPresetId )) )
+ p++;
+
+ if( p->mpStrPresetId )
+ {
+ pUserData[nSize].Value <<= OUString::createFromAscii( p->mpStrPresetId );
+ }
+ else
+ {
+ OUStringBuffer sBuffer;
+ sBuffer.append( "ppt_" );
+ switch( nEffectPresetClass )
+ {
+ case EffectPresetClass::ENTRANCE: sBuffer.append( "entrance_" ); break;
+ case EffectPresetClass::EXIT: sBuffer.append( "exit_" ); break;
+ case EffectPresetClass::EMPHASIS: sBuffer.append( "emphasis_" ); break;
+ case EffectPresetClass::MOTIONPATH: sBuffer.append( "motionpath_" ); break;
+ case EffectPresetClass::OLEACTION: sBuffer.append( "oleaction_" ); break;
+ case EffectPresetClass::MEDIACALL: sBuffer.append( "mediacall_" ); break;
+ }
+ sBuffer.append( nPresetId );
+
+ pUserData[nSize].Value <<= sBuffer.makeStringAndClear();
+ }
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_PRESET_SUB_TYPE ) )
+ {
+ sal_Int32 nPresetSubType = 0;
+ if( rSet.getProperty( DFF_ANIM_PRESET_SUB_TYPE ) >>= nPresetSubType )
+ {
+ if( nPresetSubType )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "preset-sub-type";
+ pUserData[nSize].Value <<= oox::ppt::getConvertedSubType( nEffectPresetClass, nPresetId, nPresetSubType );
+ }
+ }
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_AFTEREFFECT ) )
+ {
+ if( rSet.getProperty( DFF_ANIM_AFTEREFFECT ) >>= bAfterEffect )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "after-effect";
+ pUserData[nSize].Value <<= bAfterEffect;
+ }
+ }
+
+ if( bAfterEffect && rSet.hasProperty( DFF_ANIM_MASTERREL ) )
+ {
+ sal_Int32 nMasterRel = 2;
+ if( rSet.getProperty( DFF_ANIM_MASTERREL ) >>= nMasterRel )
+ {
+ sal_Int32 nSize = aUserData.getLength();
+ aUserData.realloc(nSize+1);
+ auto pUserData = aUserData.getArray();
+ pUserData[nSize].Name = "master-rel";
+ pUserData[nSize].Value <<= nMasterRel;
+ }
+ }
+
+ xNode->setUserData( aUserData );
+
+ // TODO: DFF_ANIM_ID
+ if( rSet.hasProperty( DFF_ANIM_ID ) )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_ID ) >>= aString;
+ //if( !aString.isEmpty() )
+ //{
+ //}
+ }
+
+ // TODO: DFF_ANIM_EVENT_FILTER
+ if( rSet.hasProperty( DFF_ANIM_EVENT_FILTER ) )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_EVENT_FILTER ) >>= aString;
+ //if( !aString.isEmpty() )
+ //{
+ //}
+ }
+
+ // DFF_ANIM_TIMEFILTER
+ if( rSet.hasProperty( DFF_ANIM_TIMEFILTER ) )
+ {
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+ if( xAnim.is() )
+ {
+ OUString aString;
+ rSet.getProperty( DFF_ANIM_TIMEFILTER ) >>= aString;
+ if( !aString.isEmpty() )
+ {
+ sal_Int32 nElements = 1; // a non empty string has at least one value
+
+ sal_Int32 fromIndex = 0;
+ while(true)
+ {
+ fromIndex = aString.indexOf( ';', fromIndex );
+ if( fromIndex == -1 )
+ break;
+
+ fromIndex++;
+ nElements++;
+ }
+
+ Sequence< TimeFilterPair > aTimeFilter( nElements );
+
+ TimeFilterPair* pValues = aTimeFilter.getArray();
+ sal_Int32 nIndex = 0;
+ while( (nElements--) && (nIndex >= 0) )
+ {
+ const std::u16string_view aToken( o3tl::getToken(aString, 0, ';', nIndex ) );
+
+ size_t nPos = aToken.find( ',' );
+ if( nPos != std::u16string_view::npos )
+ {
+ pValues->Time = o3tl::toDouble(aToken.substr( 0, nPos ));
+ pValues->Progress = o3tl::toDouble(aToken.substr( nPos+1 ));
+ }
+ pValues++;
+ }
+
+ xAnim->setTimeFilter( aTimeFilter );
+ }
+ }
+ }
+
+// TODO: DFF_ANIM_ENDAFTERSLIDE / DFF_ANIM_VOLUME handling. git history has sample code
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+ if( !xColor.is() )
+ return;
+
+ if( rSet.hasProperty( DFF_ANIM_DIRECTION ) )
+ {
+ bool bDirection = false;
+ if( rSet.getProperty( DFF_ANIM_DIRECTION ) >>= bDirection )
+ xColor->setDirection( !bDirection );
+ }
+
+ if( rSet.hasProperty( DFF_ANIM_COLORSPACE ) )
+ {
+ sal_Int32 nColorSpace = 0;
+ rSet.getProperty( DFF_ANIM_COLORSPACE ) >>= nColorSpace;
+ xColor->setColorInterpolation( (nColorSpace == 0) ? AnimationColorSpace::RGB : AnimationColorSpace::HSL );
+ }
+}
+
+int AnimationImporter::importTimeContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importTimeContainer()!");
+ if( pAtom && xNode.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ dump(">\n");
+
+ // import sub containers
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimSubGoup :
+ {
+ if( pChildAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ {
+ Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext();
+ Reference< XAnimationNode > xChildNode( Command::create(xContext), UNO_QUERY_THROW );
+ nNodes += importAnimationNodeContainer( pChildAtom, xChildNode );
+ Reference< XTimeContainer > xParentContainer( xNode, UNO_QUERY );
+ if( xParentContainer.is() && xChildNode.is() )
+ xParentContainer->appendChild( xChildNode );
+ }
+ else
+ {
+ nNodes += importAnimationContainer( pChildAtom, xNode );
+ }
+ }
+ break;
+ case DFF_msofbtAnimGroup :
+ {
+ nNodes += importAnimationContainer( pChildAtom, xNode );
+ }
+ break;
+ case DFF_msofbtAnimIteration:
+ {
+ if( pChildAtom->seekToContent() )
+ {
+ float fInterval(0.0);
+ sal_Int32 nTextUnitEffect(0), nU1(0), nU2(0), nU3(0);
+
+ mrStCtrl.ReadFloat( fInterval ).ReadInt32( nTextUnitEffect ).ReadInt32( nU1 ).ReadInt32( nU2 ).ReadInt32( nU3 );
+
+ Reference< XIterateContainer > xIter( xNode, UNO_QUERY );
+ if( xIter.is() )
+ {
+ sal_Int16 nIterateType = TextAnimationType::BY_PARAGRAPH;
+ switch( nTextUnitEffect )
+ {
+ case 1: nIterateType = TextAnimationType::BY_WORD; break;
+ case 2: nIterateType = TextAnimationType::BY_LETTER; break;
+ }
+ xIter->setIterateType( nIterateType );
+ xIter->setIterateInterval( static_cast<double>(fInterval) );
+ }
+
+ nNodes++;
+
+ dump( "<iterate" );
+ dump( " iterateType=\"%s\"", (nTextUnitEffect == 0) ? "byElement" : (nTextUnitEffect == 1) ? "byWord" : "byLetter" );
+ dump( " iterateInterval=\"%g\"", fInterval );
+ dump( " u1=\"%ld\"", nU1 );
+ dump( " u2=\"%ld\"", nU2 );
+ dump( " u3=\"%ld\"/>\n", nU3 );
+ }
+ }
+ break;
+
+ case 0xf136:
+ {
+#ifdef DBG_ANIM_LOG
+ sal_uInt32 nU1, nU2;
+ mrStCtrl.ReadUInt32(nU1).ReadUInt32(nU2);
+
+ fprintf( mpFile, "<unknown_0xf136 nU1=\"%" SAL_PRIdINT32 "\" nU2=\"%" SAL_PRIdINT32 "\"/>\n", nU1, nU2 );
+#endif
+ }
+ break;
+
+ default:
+ {
+ dump_atom_header( pChildAtom, true, false );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, false );
+ }
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ return nNodes;
+}
+
+int AnimationImporter::importAnimationNodeContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importAnimationNodeContainer()!");
+ if( pAtom && xNode.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ nNodes ++;
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimateFilter:
+ importAnimateFilterContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateSet:
+ importAnimateSetContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimate:
+ importAnimateContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateScale:
+ importAnimateScaleContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateColor:
+ importAnimateColorContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateRotation:
+ importAnimateRotationContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimateMotion:
+ importAnimateMotionContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimCommand:
+ importCommandContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ {
+ nNodes --;
+ dump_atom_header( pChildAtom, true, false );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, false );
+ }
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ return nNodes;
+}
+
+void AnimationImporter::importAnimateFilterContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateFilter && xFilter.is(), "invalid call to ppt::AnimationImporter::importAnimateFilterContainer()!");
+ if( !(pAtom && xFilter.is()) )
+ return;
+
+ sal_uInt32 nBits = 0;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateFilterData:
+ {
+ sal_uInt32 transition(0);
+ mrStCtrl.ReadUInt32( nBits );
+ mrStCtrl.ReadUInt32( transition );
+
+ if( nBits & 1 )
+ xFilter->setMode( transition == 0 );
+
+ dump( " transition=\"%s\"", (transition == 0) ? "in" : "out" );
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ if( (nBits & 2 ) && ( pChildAtom->getInstance() == 1 ) )
+ {
+ Any aAny;
+ if ( importAttributeValue( pChildAtom, aAny ) )
+ {
+ OUString filter;
+ aAny >>= filter;
+
+ dump( " filter=\"%s\"", filter );
+
+ const oox::ppt::transition* pTransition = oox::ppt::transition::find( filter );
+ if( pTransition )
+ {
+ xFilter->setTransition( pTransition->mnType );
+ xFilter->setSubtype( pTransition->mnSubType );
+ xFilter->setDirection( pTransition->mbDirection );
+ }
+ else
+ {
+ OSL_FAIL( "unknown transition!" );
+ }
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateAttributeTargetContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateTarget, "invalid call to ppt::AnimationImporter::importAnimateAttributeTargetContainer()!");
+
+ Any aTarget;
+
+ Reference< XAnimate > xAnimate( xNode, UNO_QUERY );
+
+ bool bWrongContext = false;
+
+ if( pAtom )
+ {
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimPropertySet:
+ {
+ PropertySet aSet;
+ importPropertySetContainer( pChildAtom, aSet );
+ if( aSet.hasProperty( DFF_ANIM_RUNTIMECONTEXT ) )
+ {
+ OUString aContext;
+ if( aSet.getProperty( DFF_ANIM_RUNTIMECONTEXT ) >>= aContext )
+ {
+ if( aContext != "PPT" )
+ bWrongContext = true;
+ }
+ }
+
+ dump( aSet );
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetSettings:
+ {
+ if( xAnimate.is() )
+ {
+ sal_uInt32 nBits(0);
+ sal_uInt32 nAdditive(0);
+ sal_uInt32 nAccumulate(0);
+ sal_uInt32 nTransformType(0);
+
+ mrStCtrl.ReadUInt32( nBits ).ReadUInt32( nAdditive ).ReadUInt32( nAccumulate ).ReadUInt32( nTransformType );
+
+ // nBits %0001: additive, %0010: accumulate, %0100: attributeName, %1000: transformtype
+ // nAdditive 0 = base, 1 = sum, 2 = replace, 3 = multiply, 4 = none
+ // nAccumulate 0 = none, 1 = always
+ // nTransformType 0: "property" else "image"
+
+ if( nBits & 3 && xAnimate.is() )
+ {
+ if( nBits & 1 )
+ {
+ sal_Int16 nTemp = AnimationAdditiveMode::BASE;
+ switch( nAdditive )
+ {
+ case 1: nTemp = AnimationAdditiveMode::SUM; break;
+ case 2: nTemp = AnimationAdditiveMode::REPLACE; break;
+ case 3: nTemp = AnimationAdditiveMode::MULTIPLY; break;
+ case 4: nTemp = AnimationAdditiveMode::NONE; break;
+ }
+ xAnimate->setAdditive( nTemp );
+ }
+
+ if( nBits & 2 )
+ {
+ xAnimate->setAccumulate( nAccumulate == 0 );
+ }
+ }
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " additive=\"%s\"", (nAdditive == 0) ? "base" : (nAdditive == 2) ? "replace" : (nAdditive == 1) ? "sum" : (nAdditive == 3 ) ? "multiply" : (nAdditive == 4) ? "none" : "unknown" );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " accumulate=\"%s\"", (nAccumulate == 0) ? "none" : "always" );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " transformType=\"%s\"", (nTransformType == 0) ? "property" : "image" );
+#endif
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateAttributeNames:
+ {
+ if( xAnimate.is() )
+ {
+ OUString aAttributeName;
+ importAttributeNamesContainer( pChildAtom, aAttributeName );
+ if( xAnimate.is() )
+ xAnimate->setAttributeName( aAttributeName );
+ dump( " attributeName=\"%s\"", aAttributeName );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ importTargetElementContainer( pChildAtom, aTarget, nSubType );
+ if( xAnimate.is() )
+ xAnimate->setSubItem( nSubType );
+
+ dump( " target=\"" );
+ dump_target( aTarget );
+ dump( "\"" );
+ }
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+ }
+
+ if( bWrongContext )
+ aTarget.clear();
+
+ if( xAnimate.is() )
+ xAnimate->setTarget( aTarget );
+ else
+ {
+ Reference< XCommand > xCommand( xNode, UNO_QUERY );
+ if( xCommand.is() )
+ xCommand->setTarget( aTarget );
+ }
+}
+
+sal_Int16 AnimationImporter::implGetColorSpace( sal_Int32 nMode, sal_Int32 /*nA*/, sal_Int32 /*nB*/, sal_Int32 /*nC*/ )
+{
+ switch( nMode )
+ {
+ case 2: // index
+ default:
+ case 0: // rgb
+ return AnimationColorSpace::RGB;
+
+ case 1: // hsl
+ return AnimationColorSpace::HSL;
+ }
+}
+
+Any AnimationImporter::implGetColorAny( sal_Int32 nMode, sal_Int32 nA, sal_Int32 nB, sal_Int32 nC )
+{
+ switch( nMode )
+ {
+ case 0: // rgb
+ {
+ dump( "rgb(%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ Color aColor( static_cast<sal_uInt8>(nA), static_cast<sal_uInt8>(nB), static_cast<sal_uInt8>(nC) );
+ return Any( static_cast<sal_Int32>(aColor.GetRGBColor()) );
+ }
+ case 1: // hsl
+ {
+ dump( "hsl(%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ Sequence< double > aHSL{ nA * 360.0/255.0,
+ nB / 255.0,
+ nC / 255.0 };
+ return Any( aHSL );
+ }
+
+ case 2: // index
+ {
+ Color aColor;
+ mpPPTImport->GetColorFromPalette(static_cast<sal_uInt16>(nA), aColor );
+ dump( "index(%ld", nA );
+ dump( " [%ld", static_cast<sal_Int32>(aColor.GetRed()) );
+ dump( ",%ld", static_cast<sal_Int32>(aColor.GetGreen()) );
+ dump( ",%ld])", static_cast<sal_Int32>(aColor.GetBlue()) );
+ return Any( static_cast<sal_Int32>(aColor.GetRGBColor()) );
+ }
+
+ default:
+ {
+ dump( "unknown_%ld(", nMode );
+ dump( "%ld", nA );
+ dump( ",%ld", nB );
+ dump( ",%ld)", nC );
+ OSL_FAIL( "ppt::implGetColorAny(), unhandled color type" );
+
+ Any aAny;
+ return aAny;
+ }
+ }
+}
+
+void AnimationImporter::importAnimateColorContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateColor && xColor.is(), "invalid call to ppt::AnimationImporter::importAnimateColorContainer()!");
+ if( !(pAtom && xColor.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateColorData:
+ {
+ sal_uInt32 nBits;
+ sal_Int32 nByMode, nByA, nByB, nByC;
+ sal_Int32 nFromMode, nFromA, nFromB, nFromC;
+ sal_Int32 nToMode, nToA, nToB, nToC;
+ mrStCtrl.ReadUInt32( nBits );
+ mrStCtrl.ReadInt32( nByMode ).ReadInt32( nByA ).ReadInt32( nByB ).ReadInt32( nByC );
+ mrStCtrl.ReadInt32( nFromMode ).ReadInt32( nFromA ).ReadInt32( nFromB ).ReadInt32( nFromC );
+ mrStCtrl.ReadInt32( nToMode ).ReadInt32( nToA ).ReadInt32( nToB ).ReadInt32( nToC );
+
+ if (!mrStCtrl.good())
+ {
+ SAL_WARN("filter.ms", "DFF_msofbtAnimateColorData: short read");
+ break;
+ }
+
+ if( nBits & 1 )
+ {
+ dump( " by=\"" );
+ xColor->setBy( implGetColorAny( nByMode, nByA, nByB, nByC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nByMode, nByA, nByB, nByC ) );
+ dump( "\"");
+ }
+
+ if( nBits & 2 )
+ {
+ dump( " from=\"" );
+ xColor->setFrom( implGetColorAny( nFromMode, nFromA, nFromB, nFromC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nFromMode, nFromA, nFromB, nFromC ) );
+ dump( "\"");
+ }
+
+ if( nBits & 4 )
+ {
+ dump( " to=\"" );
+ xColor->setTo( implGetColorAny( nToMode, nToA, nToB, nToC ) );
+ xColor->setColorInterpolation( implGetColorSpace( nToMode, nToA, nToB, nToC ) );
+ dump( "\"");
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateSetContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateSet > xSet( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateSet && xSet.is(), "invalid call to ppt::AnimationImporter::importAnimateSetContainer()!");
+ if( !(pAtom && xSet.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateSetData:
+ {
+ sal_Int32 nU1, nU2;
+ mrStCtrl.ReadInt32( nU1 ).ReadInt32( nU2 );
+
+ dump( " set_1=\"%ld\"", nU1 );
+ dump( " set_2=\"%ld\"", nU2 );
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aTo;
+ if ( importAttributeValue( pChildAtom, aTo ) )
+ {
+ xSet->setTo( aTo );
+
+ dump( " value=\"" );
+ dump( aTo );
+ dump( "\"" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimate && xAnim.is(), "invalid call to ppt::AnimationImporter::importAnimateContainer()!");
+ if( !(pAtom && xAnim.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateData:
+ {
+ sal_uInt32 nCalcmode(0), nBits(0), nValueType(0);
+ mrStCtrl.ReadUInt32( nCalcmode ).ReadUInt32( nBits ).ReadUInt32( nValueType );
+
+ if( nBits & 0x08 )
+ {
+ sal_Int16 n = (nCalcmode == 1) ? AnimationCalcMode::LINEAR : /* (nCalcmode == 2) ? AnimationCalcMode::FORMULA : */ AnimationCalcMode::DISCRETE;
+ xAnim->setCalcMode( n );
+ dump( " calcmode=\"%s\"", (nCalcmode == 0) ? "discrete" : (nCalcmode == 1) ? "linear" : (nCalcmode == 2) ? "formula" : "unknown" );
+ }
+
+ if( nBits & 0x30 )
+ {
+ sal_Int16 n = (nValueType == 1) ? AnimationValueType::NUMBER : (nValueType == 2 ) ? AnimationValueType::COLOR : AnimationValueType::STRING;
+ xAnim->setValueType( n );
+ dump( " valueType=\"%s\"", (nValueType == 0) ? "string" : (nValueType == 1) ? "number" : (nValueType == 2) ? "color" : "unknown" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimKeyPoints:
+ importAnimateKeyPoints( pChildAtom, xNode );
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any a;
+ if ( importAttributeValue( pChildAtom, a ) )
+ {
+ switch( pChildAtom->getInstance() )
+ {
+ case 1: xAnim->setBy( a ); dump( " by=\"" ); break;
+ case 2: xAnim->setFrom( a ); dump( " from=\"" ); break;
+ case 3: xAnim->setTo( a ); dump( " to=\"" ); break;
+ default:
+ dump( " unknown_value=\"" );
+ }
+
+ dump( a );
+ dump( "\"" );
+ }
+ }
+ break;
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateMotionContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateMotion && xMotion.is(), "invalid call to ppt::AnimationImporter::importAnimateMotionContainer()!");
+ if( !(pAtom && xMotion.is()) )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateMotionData:
+ {
+ sal_uInt32 nBits, nOrigin;
+ float fByX, fByY, fFromX, fFromY, fToX, fToY;
+
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fByX ).ReadFloat( fByY ).ReadFloat( fFromX ).ReadFloat( fFromY ).ReadFloat( fToX ).ReadFloat( fToY ).ReadUInt32( nOrigin );
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g,%g\"", (double)fByX, (double)fByY );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g,%g\"", (double)fFromX, (double)fFromY );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g,%g\"", (double)fToX, (double)fToY );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " origin=\"%s\"", (nOrigin == 1) ? "parent" : (nOrigin == 2) ? "layout" : "unknown" );
+
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aPath;
+ if ( importAttributeValue( pChildAtom, aPath ) )
+ {
+ OUString aStr;
+ if ( aPath >>= aStr )
+ {
+ // E can appear inside a number, so we only check for its presence at the end
+ aStr = aStr.trim();
+ if (aStr.endsWith("E"))
+ aStr = aStr.copy(0, aStr.getLength() - 1);
+ aStr = aStr.trim();
+ aPath <<= aStr;
+ xMotion->setPath( aPath );
+ dump( " path=\"" );
+ dump( aPath );
+ dump( "\"" );
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importCommandContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XCommand > xCommand( xNode, UNO_QUERY );
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimCommand && xCommand.is(), "invalid call to ppt::AnimationImporter::importCommandContainer()!");
+ if( !(pAtom && xCommand.is()) )
+ return;
+
+ sal_Int32 nBits = 0;
+ Any aValue;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtCommandData:
+ {
+ sal_Int32 nCommandType;
+ // looks like U1 is a bitset, bit 1 enables the type and bit 2 enables
+ // a propertyvalue that follows
+ mrStCtrl.ReadInt32( nBits );
+ mrStCtrl.ReadInt32( nCommandType );
+
+ if( nBits & 1 )
+ {
+ dump( " type=\"%s\"", (nCommandType == 0) ? "event" : ( nCommandType == 1) ? "call" : "verb" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ if ( importAttributeValue( pChildAtom, aValue ) )
+ {
+ if( nBits & 2 )
+ {
+ dump( " cmd=\"" );
+ dump( aValue );
+ dump( "\"" );
+ }
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ if( !(nBits & 3) )
+ return;
+
+ OUString aParam;
+ aValue >>= aParam;
+
+ sal_Int16 nCommand = EffectCommands::CUSTOM;
+
+ NamedValue aParamValue;
+
+ if ( aParam == "onstopaudio" )
+ {
+ nCommand = EffectCommands::STOPAUDIO;
+ }
+ else if ( aParam == "play" )
+ {
+ nCommand = EffectCommands::PLAY;
+ }
+ else if( aParam.startsWith( "playFrom" ) )
+ {
+ const std::u16string_view aMediaTime( aParam.subView( 9, aParam.getLength() - 10 ) );
+ rtl_math_ConversionStatus eStatus;
+ double fMediaTime = ::rtl::math::stringToDouble( aMediaTime, u'.', u',', &eStatus );
+ if( eStatus == rtl_math_ConversionStatus_Ok )
+ {
+ aParamValue.Name = "MediaTime";
+ aParamValue.Value <<= fMediaTime;
+ }
+ nCommand = EffectCommands::PLAY;
+ }
+ else if ( aParam == "togglePause" )
+ {
+ nCommand = EffectCommands::TOGGLEPAUSE;
+ }
+ else if ( aParam == "stop" )
+ {
+ nCommand = EffectCommands::STOP;
+ }
+
+ xCommand->setCommand( nCommand );
+ if( nCommand == EffectCommands::CUSTOM )
+ {
+ OSL_FAIL("sd::AnimationImporter::importCommandContainer(), unknown command!");
+ aParamValue.Name = "UserDefined";
+ aParamValue.Value <<= aParam;
+ }
+
+ if( aParamValue.Value.hasValue() )
+ {
+ Sequence< NamedValue > aParamSeq( &aParamValue, 1 );
+ xCommand->setParameter( Any( aParamSeq ) );
+ }
+}
+
+int AnimationImporter::importAudioContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ int nNodes = 0;
+
+ Reference< XAudio > xAudio( xNode, UNO_QUERY );
+ DBG_ASSERT( pAtom && xAudio.is() &&
+ ( (pAtom->getType() == DFF_msofbtAnimGroup) ||
+ (pAtom->getType() == DFF_msofbtAnimSubGoup) ), "invalid call to ppt::AnimationImporter::importAudioContainer()!");
+ if( pAtom && xAudio.is() )
+ {
+ importAnimationEvents( pAtom, xNode );
+ importAnimationValues( pAtom, xNode );
+ importAnimationActions( pAtom, xNode );
+
+ dump(">\n");
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimNode:
+ case DFF_msofbtAnimEvent:
+ case DFF_msofbtAnimValue:
+ case DFF_msofbtAnimAction:
+ case DFF_msofbtAnimPropertySet:
+ break;
+
+ case DFF_msofbtAnimAttributeValue:
+ {
+ Any aValue;
+ if ( importAttributeValue( pChildAtom, aValue ) )
+ {
+ nNodes ++;
+ dump( " value=\"" );
+ dump( aValue );
+ dump( "\"" );
+ }
+ }
+ break;
+
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ Any aSource;
+ importTargetElementContainer( pChildAtom, aSource, nSubType );
+ if( xAudio.is() ) {
+ xAudio->setSource( aSource );
+ nNodes ++;
+ }
+ }
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ // TODO: What to do with them?
+ Any aEmpty;
+ xAudio->setBegin( aEmpty );
+ xAudio->setEnd( aEmpty );
+ }
+
+ return nNodes;
+}
+
+void AnimationImporter::importAnimateScaleContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateScale && xTransform.is(), "invalid call to ppt::AnimationImporter::importAnimateScaleContainer()!");
+ if( !(pAtom && xTransform.is()) )
+ return;
+
+ xTransform->setTransformType( AnimationTransformType::SCALE );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateScaleData:
+ {
+ sal_uInt32 nBits(0), nZoomContents(0);
+ float fByX(0.0), fByY(0.0), fFromX(0.0), fFromY(0.0), fToX(0.0), fToY(0.0);
+
+ // nBits %001: by, %010: from, %100: to, %1000: zoomContents(bool)
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fByX ).ReadFloat( fByY ).ReadFloat( fFromX ).ReadFloat( fFromY ).ReadFloat( fToX ).ReadFloat( fToY ).ReadUInt32( nZoomContents );
+
+ ValuePair aPair;
+ // 'from' value
+ if( nBits & 2 )
+ {
+ aPair.First <<= static_cast<double>(fFromX) / 100.0;
+ aPair.Second <<= static_cast<double>(fFromY) / 100.0;
+ xTransform->setFrom( Any( aPair ) );
+ }
+
+ // 'to' value
+ if( nBits & 4 )
+ {
+ aPair.First <<= static_cast<double>(fToX) / 100.0;
+ aPair.Second <<= static_cast<double>(fToY) / 100.0;
+ xTransform->setTo( Any( aPair ) );
+ }
+
+ // 'by' value
+ if( nBits & 1 )
+ {
+ aPair.First <<= static_cast<double>(fByX) / 100.0;
+ aPair.Second <<= static_cast<double>(fByY) / 100.0;
+
+ if( nBits & 2 )
+ {
+ // 'from' value given, import normally
+ xTransform->setBy( Any( aPair ) );
+ }
+ else
+ {
+ // mapping 'by' to 'to', if no 'from' is
+ // given. This is due to a non-conformity in
+ // PPT, which exports animateScale effects
+ // with a sole 'by' value, but with the
+ // semantics of a sole 'to' animation
+ xTransform->setTo( Any( aPair ) );
+ }
+ }
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g,%g\"", (double)fByX, (double)fByY );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g,%g\"", (double)fFromX, (double)fFromY );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g,%g\"", (double)fToX, (double)fToY );
+
+ if( nBits & 8 )
+ fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAnimateRotationContainer( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimateRotation && xTransform.is(), "invalid call to ppt::AnimationImporter::importAnimateRotationContainer()!");
+ if( !(pAtom && xTransform.is()) )
+ return;
+
+ xTransform->setTransformType( AnimationTransformType::ROTATE );
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+
+ while( pChildAtom )
+ {
+ if( !pChildAtom->isContainer() )
+ {
+ if( !pChildAtom->seekToContent() )
+ break;
+ }
+
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimateRotationData:
+ {
+ sal_uInt32 nBits(0), nU1(0);
+ float fBy(0.0), fFrom(0.0), fTo(0.0);
+
+ // nBits %001: by, %010: from, %100: to, %1000: zoomContents(bool)
+ mrStCtrl.ReadUInt32( nBits ).ReadFloat( fBy ).ReadFloat( fFrom ).ReadFloat( fTo ).ReadUInt32( nU1 );
+
+ if( nBits & 1 )
+ xTransform->setBy( Any( static_cast<double>(fBy) ) );
+
+ if( nBits & 2 )
+ xTransform->setFrom( Any( static_cast<double>(fFrom) ) );
+
+ if( nBits & 4 )
+ xTransform->setTo( Any( static_cast<double>(fTo) ) );
+
+#ifdef DBG_ANIM_LOG
+ if( nBits & 1 )
+ fprintf( mpFile, " by=\"%g\"", (double)fBy );
+
+ if( nBits & 2 )
+ fprintf( mpFile, " from=\"%g\"", (double)fFrom );
+
+ if( nBits & 4 )
+ fprintf( mpFile, " to=\"%g\"", (double)fTo );
+
+ if( nU1 )
+ fprintf( mpFile, " rotation_1=\"%" SAL_PRIdINT32 "\"", nU1 );
+#endif
+ }
+ break;
+
+ case DFF_msofbtAnimateTarget:
+ importAnimateAttributeTargetContainer( pChildAtom, xNode );
+ break;
+
+ default:
+ dump( " unknown_atom=\"%ld\"", static_cast<sal_Int32>(pChildAtom->getType()) );
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+void AnimationImporter::importAttributeNamesContainer( const Atom* pAtom, OUString& rAttributeNames )
+{
+ OUStringBuffer aNames;
+
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimateAttributeNames), "invalid call to ppt::AnimationImporter::importAttributeName()!" );
+ if( pAtom )
+ {
+ const Atom* pAttributeValueAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimAttributeValue );
+
+ while( pAttributeValueAtom )
+ {
+ Any aAny;
+ if ( importAttributeValue( pAttributeValueAtom, aAny ) )
+ {
+ OUString aName;
+ if( aAny >>= aName )
+ {
+ if( !aNames.isEmpty() )
+ aNames.append( ';' );
+
+ aNames.append( aName );
+ }
+ }
+ else
+ {
+ OSL_FAIL( "error during ppt::AnimationImporter::importAttributeName()!" );
+ }
+
+ pAttributeValueAtom = pAtom->findNextChildAtom( DFF_msofbtAnimAttributeValue, pAttributeValueAtom );
+ }
+ }
+
+ rAttributeNames = aNames.makeStringAndClear();
+}
+
+void AnimationImporter::importAnimationValues( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom, "invalid call to ppt::AnimationImporter::importAnimationValues()!" );
+
+ if( !pAtom )
+ return;
+
+ const Atom* pValueAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimValue );
+
+ while( pValueAtom && pValueAtom->seekToContent() )
+ {
+ sal_uInt32 nType(0);
+ mrStCtrl.ReadUInt32( nType );
+ switch( nType )
+ {
+ case 0:
+ {
+ float fRepeat(0.0);
+ mrStCtrl.ReadFloat( fRepeat );
+ xNode->setRepeatCount( (fRepeat < (float(3.40282346638528860e+38))) ? Any( static_cast<double>(fRepeat) ) : Any( Timing_INDEFINITE ) );
+
+#ifdef DBG_ANIM_LOG
+ if( (fRepeat < ((float)3.40282346638528860e+38)) )
+ {
+ dump( " repeat=\"%g\"", (double)fRepeat );
+ }
+ else
+ {
+ dump( " repeat=\"indefinite\"" );
+ }
+#endif
+ }
+ break;
+
+ case 3:
+ {
+ float faccelerate(0.0);
+ mrStCtrl.ReadFloat( faccelerate );
+ xNode->setAcceleration( faccelerate );
+ dump( " accelerate=\"%g\"", static_cast<double>(faccelerate) );
+ }
+ break;
+
+ case 4:
+ {
+ float fdecelerate(0.0);
+ mrStCtrl.ReadFloat( fdecelerate );
+ xNode->setDecelerate( fdecelerate );
+ dump( " decelerate=\"%g\"", static_cast<double>(fdecelerate) );
+ }
+ break;
+
+ case 5:
+ {
+ sal_Int32 nAutoreverse(0);
+ mrStCtrl.ReadInt32( nAutoreverse );
+ xNode->setAutoReverse( nAutoreverse != 0 );
+ dump( " autoreverse=\"%#lx\"", nAutoreverse );
+ }
+ break;
+
+ default:
+ {
+ sal_uInt32 nUnknown;
+ mrStCtrl.ReadUInt32( nUnknown );
+#ifdef DBG_ANIM_LOG
+ fprintf(mpFile, " attribute_%d=\"%#lx\"", nType, nUnknown );
+#endif
+ }
+ break;
+ }
+
+ pValueAtom = pAtom->findNextChildAtom( DFF_msofbtAnimValue, pValueAtom );
+ }
+}
+
+void AnimationImporter::importAnimateKeyPoints( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ Reference< XAnimate > xAnim( xNode, UNO_QUERY );
+
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimKeyPoints && xAnim.is(), "invalid call to ppt::AnimationImporter::importAnimateKeyPoints()!" );
+
+ if( !(pAtom && xAnim.is()) )
+ return;
+
+ // first count keytimes
+ const Atom* pIter = nullptr;
+ int nKeyTimes = 0;
+
+ while( (pIter = pAtom->findNextChildAtom( DFF_msofbtAnimKeyTime, pIter )) != nullptr )
+ nKeyTimes++;
+
+ Sequence< double > aKeyTimes( nKeyTimes );
+ auto aKeyTimesRange = asNonConstRange(aKeyTimes);
+ Sequence< Any > aValues( nKeyTimes );
+ auto aValuesRange = asNonConstRange(aValues);
+ OUString aFormula;
+
+ pIter = pAtom->findFirstChildAtom(DFF_msofbtAnimKeyTime);
+ bool bToNormalize = false;
+ for( int nKeyTime = 0; (nKeyTime < nKeyTimes) && pIter; nKeyTime++ )
+ {
+ if( pIter->seekToContent() )
+ {
+ sal_Int32 nTemp(0);
+ mrStCtrl.ReadInt32(nTemp);
+ double fTemp = static_cast<double>(nTemp) / 1000.0;
+ aKeyTimesRange[nKeyTime] = fTemp;
+ if( fTemp == -1 )
+ bToNormalize = true;
+
+ const Atom* pValue = Atom::findNextChildAtom(pIter);
+ if( pValue && pValue->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ Any aValue1, aValue2;
+ if( importAttributeValue( pValue, aValue1 ) )
+ {
+ pValue = Atom::findNextChildAtom(pValue);
+ if( pValue && pValue->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ // Any occurrence of the formula becomes the formula of the whole list.
+ if (importAttributeValue(pValue, aValue2) && aFormula.isEmpty())
+ aValue2 >>= aFormula;
+ }
+ aValuesRange[nKeyTime] = aValue1;
+ }
+ }
+ }
+ pIter = pAtom->findNextChildAtom(DFF_msofbtAnimKeyTime, pIter);
+ }
+
+#ifdef DBG_ANIM_LOG
+ dump( " keyTimes=\"" );
+ for( int i=0; i<nKeyTimes; ++i )
+ dump( "%f;", aKeyTimes[i] );
+
+ if( !aFormula.isEmpty() )
+ {
+ dump( "formula=\"%s", aFormula );
+ }
+
+ dump( "\" values=\"" );
+ double nVal;
+ OUString aStr;
+ for( int i=0; i<nKeyTimes; ++i )
+ {
+ if( i != 0 )
+ dump( ";" );
+
+ if( aValues[i] >>= aStr )
+ dump( "%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValues[i] >>= nVal )
+ dump( "%f", nVal );
+ else
+ {
+ ValuePair aValuePair;
+
+ if( aValues[i] >>= aValuePair )
+ {
+ if( aValuePair.First >>= aStr )
+ dump( "%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValuePair.First >>= nVal )
+ dump( "%f", nVal );
+ else
+ dump( "%X", (sal_Int64)&aValuePair.First );
+
+ if( aValuePair.Second >>= aStr )
+ dump( ",%s",
+ OUStringToOString( aStr,
+ RTL_TEXTENCODING_ASCII_US ).getStr() );
+ else if( aValuePair.Second >>= nVal )
+ dump( ",%f", nVal );
+ else
+ dump( ",%X", (sal_Int64)&aValuePair.Second );
+ }
+ }
+ }
+ dump( "\"" );
+#endif
+ if( bToNormalize && nKeyTimes >= 2 )
+ {
+ // if TimeAnimationValueList contains time -1000, key points must be evenly distributed between 0 and 1 ([MS-PPT] 2.8.31)
+ for( int nKeyTime = 0; nKeyTime < nKeyTimes; ++nKeyTime )
+ {
+ aKeyTimesRange[nKeyTime] = static_cast<double>(nKeyTime) / static_cast<double>(nKeyTimes - 1);
+ }
+ }
+
+ if (aValues.getLength() != aKeyTimes.getLength())
+ throw css::io::WrongFormatException();
+
+ xAnim->setKeyTimes( aKeyTimes );
+ xAnim->setValues( aValues );
+ xAnim->setFormula( aFormula );
+}
+
+bool AnimationImporter::importAttributeValue( const Atom* pAtom, Any& rAny )
+{
+ DBG_ASSERT( pAtom && pAtom->getType() == DFF_msofbtAnimAttributeValue, "invalid call to ppt::AnimationImporter::importAttributeValue()!" );
+
+ bool bOk = false;
+
+ if( pAtom && pAtom->seekToContent() )
+ {
+ sal_uInt32 nRecLen = pAtom->getLength();
+ if ( nRecLen >= 1 )
+ {
+ sal_Int8 nType(0);
+ mrStCtrl.ReadSChar( nType );
+ switch( nType )
+ {
+ case DFF_ANIM_PROP_TYPE_BYTE :
+ {
+ if ( nRecLen == 2 )
+ {
+ sal_uInt8 nByte(0);
+ mrStCtrl.ReadUChar( nByte );
+ rAny <<= nByte;
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_INT32 :
+ {
+ if ( nRecLen == 5 )
+ {
+ sal_uInt32 nInt32(0);
+ mrStCtrl.ReadUInt32( nInt32 );
+ rAny <<= nInt32;
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_FLOAT:
+ {
+ if( nRecLen == 5 )
+ {
+ float fFloat(0.0);
+ mrStCtrl.ReadFloat( fFloat );
+ rAny <<= static_cast<double>(fFloat);
+
+ bOk = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PROP_TYPE_UNISTRING :
+ {
+ if ( ( nRecLen & 1 ) && ( nRecLen > 1 ) )
+ {
+ OUString aOUString = SvxMSDffManager::MSDFFReadZString( mrStCtrl, nRecLen - 1, true );
+ rAny <<= aOUString;
+
+ bOk = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ DBG_ASSERT( bOk, "invalid value inside ppt::AnimationImporter::importAttributeValue()!" );
+ return bOk;
+}
+
+void AnimationImporter::importAnimationEvents( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( xNode.is() && pAtom, "invalid call to ppt::AnimationImporter::importAnimationEvents()!" );
+
+ Any aBegin, aEnd, aNext, aPrev;
+
+ const Atom* pEventAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimEvent );
+ while( pEventAtom )
+ {
+ Any* pEvents = nullptr;
+
+ switch( pEventAtom->getInstance() )
+ {
+ case 1: pEvents = &aBegin; break;
+ case 2: pEvents = &aEnd; break;
+ case 3: pEvents = &aNext; break;
+ case 4: pEvents = &aPrev; break;
+ }
+
+ if( pEvents )
+ {
+ Event aEvent;
+ aEvent.Trigger = EventTrigger::NONE;
+ aEvent.Repeat = 0;
+
+ const Atom* pChildAtom = pEventAtom->findFirstChildAtom();
+
+ while( pChildAtom && pChildAtom->seekToContent() )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimTrigger:
+ {
+ sal_Int32 nU1(0), nTrigger(0), nU3(0), nBegin(0);
+ mrStCtrl.ReadInt32( nU1 );
+ mrStCtrl.ReadInt32( nTrigger );
+ mrStCtrl.ReadInt32( nU3 );
+ mrStCtrl.ReadInt32( nBegin );
+
+ switch( nTrigger )
+ {
+ case 0: aEvent.Trigger = EventTrigger::NONE; break;
+ case 1: aEvent.Trigger = EventTrigger::ON_BEGIN; break;
+ case 2: aEvent.Trigger = EventTrigger::ON_END; break;
+ case 3: aEvent.Trigger = EventTrigger::BEGIN_EVENT; break;
+ case 4: aEvent.Trigger = EventTrigger::END_EVENT; break;
+ case 5: aEvent.Trigger = EventTrigger::ON_CLICK; break;
+ case 6: aEvent.Trigger = EventTrigger::ON_DBL_CLICK; break;
+ case 7: aEvent.Trigger = EventTrigger::ON_MOUSE_ENTER; break;
+ case 8: aEvent.Trigger = EventTrigger::ON_MOUSE_LEAVE; break;
+ case 9: aEvent.Trigger = EventTrigger::ON_NEXT; break;
+ case 10: aEvent.Trigger = EventTrigger::ON_PREV; break;
+ case 11: aEvent.Trigger = EventTrigger::ON_STOP_AUDIO; break;
+ }
+
+ if( (nBegin != 0) || (aEvent.Trigger == EventTrigger::NONE) )
+ aEvent.Offset = (nBegin == -1) ? Any( Timing_INDEFINITE ) : Any( nBegin / 1000.0 );
+ }
+ break;
+ case DFF_msofbtAnimateTargetElement:
+ {
+ sal_Int16 nSubType;
+ importTargetElementContainer( pChildAtom, aEvent.Source, nSubType );
+ }
+ break;
+ default:
+ {
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importAnimationEvents()!");
+ }
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+
+ *pEvents = oox::addToSequence( *pEvents, (aEvent.Trigger == EventTrigger::NONE) ? aEvent.Offset : Any( aEvent ) );
+ }
+
+ pEventAtom = pAtom->findNextChildAtom( DFF_msofbtAnimEvent, pEventAtom );
+ }
+
+ xNode->setBegin( aBegin );
+ xNode->setEnd( aEnd );
+ // TODO: xNode->setNext( aNext );
+ // TODO: xNode->setPrev( aNext );
+
+#ifdef DBG_ANIM_LOG
+ if( aBegin.hasValue() )
+ {
+ dump( " begin=\"" );
+ dump( aBegin );
+ dump( "\"" );
+ }
+
+ if( aEnd.hasValue() )
+ {
+ dump( " end=\"" );
+ dump( aEnd );
+ dump( "\"" );
+ }
+
+ if( aNext.hasValue() )
+ {
+ dump( " next=\"" );
+ dump( aNext );
+ dump( "\"" );
+ }
+
+ if( aPrev.hasValue() )
+ {
+ dump( " prev=\"" );
+ dump( aPrev );
+ dump( "\"" );
+ }
+#endif
+}
+
+void AnimationImporter::importAnimationActions( const Atom* pAtom, const Reference< XAnimationNode >& xNode )
+{
+ DBG_ASSERT( pAtom && xNode.is(), "invalid call to ppt::AnimationImporter::importAnimationActions()!");
+
+ if( !pAtom )
+ return;
+
+ const Atom* pActionAtom = pAtom->findFirstChildAtom( DFF_msofbtAnimAction );
+
+ if( !(pActionAtom && pActionAtom->seekToContent()) )
+ return;
+
+ sal_Int32 nConcurrent(0), nNextAction(0), nEndSync(0), nU4(0), nU5(0);
+ mrStCtrl.ReadInt32( nConcurrent );
+ mrStCtrl.ReadInt32( nNextAction );
+ mrStCtrl.ReadInt32( nEndSync );
+ mrStCtrl.ReadInt32( nU4 );
+ mrStCtrl.ReadInt32( nU5 );
+
+ if( nEndSync == 1 )
+ xNode->setEndSync( Any( AnimationEndSync::ALL ) );
+
+#ifdef DBG_ANIM_LOG
+ dump( " concurrent=\"%s\"", nConcurrent == 0 ? "disabled" : (nConcurrent == 1 ? "enabled" : "unknown") );
+
+ dump( " nextAction=\"%s\"", nNextAction == 0 ? "none" : (nNextAction == 1 ? "seek" : "unknown") );
+
+ if( nEndSync != 0 )
+ {
+ dump( " endSync=\"%s\"", nEndSync == 1 ? "all" : "unknown" );
+ }
+
+ dump( " action_4=\"%#lx\"", nU4 );
+ dump( " action_5=\"%#lx\"", nU5 );
+#endif
+}
+
+void AnimationImporter::importTargetElementContainer( const Atom* pAtom, Any& rTarget, sal_Int16& rSubType )
+{
+ rSubType = ShapeAnimationSubType::AS_WHOLE;
+ sal_Int32 nRefMode = -1;
+
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimateTargetElement), "invalid call to ppt::AnimationImporter::importTargetElementContainer()!" );
+ if( !pAtom )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom && pChildAtom->seekToContent() )
+ {
+ switch( pChildAtom->getType() )
+ {
+ case DFF_msofbtAnimReference:
+ {
+ sal_Int32 nRefType(0), nRefId(0);
+ sal_Int32 begin(0), end(0);
+ mrStCtrl.ReadInt32( nRefMode );
+ mrStCtrl.ReadInt32( nRefType );
+ mrStCtrl.ReadInt32( nRefId );
+ mrStCtrl.ReadInt32( begin );
+ mrStCtrl.ReadInt32( end );
+
+ switch( nRefType )
+ {
+ case 1: // shape
+ {
+ SdrObject* pSdrObject = mpPPTImport->getShapeForId( nRefId );
+ if( pSdrObject == nullptr )
+ break;
+
+ rTarget <<= pSdrObject->getUnoShape();
+
+ switch( nRefMode )
+ {
+ case 6: rSubType = ShapeAnimationSubType::ONLY_BACKGROUND; break;
+ case 8: rSubType = ShapeAnimationSubType::ONLY_TEXT; break;
+ case 2: // one paragraph
+ {
+ if((begin == -1) && (end == -1))
+ break;
+
+ SdrTextObj* pTextObj = dynamic_cast< SdrTextObj* >( pSdrObject );
+ if(!pTextObj)
+ break;
+
+ const OutlinerParaObject* pOPO = pTextObj->GetOutlinerParaObject();
+ if( pOPO == nullptr )
+ break;
+
+ const EditTextObject& rEditTextObject = pOPO->GetTextObject();
+
+ const sal_Int32 nParaCount = rEditTextObject.GetParagraphCount();
+
+ sal_Int32 nPara = 0;
+
+ while( (nPara < nParaCount) && (begin > 0) )
+ {
+ sal_Int32 nParaLength = rEditTextObject.GetText( nPara ).getLength() + 1;
+ begin -= nParaLength;
+ end -= nParaLength;
+ nPara++;
+ }
+
+ if( nPara < nParaCount )
+ {
+ ParagraphTarget aParaTarget;
+ rTarget >>= aParaTarget.Shape;
+ /* FIXME: Paragraph should be sal_Int32 as well */
+ aParaTarget.Paragraph = static_cast<sal_Int16>(nPara);
+ rTarget <<= aParaTarget;
+
+ rSubType = ShapeAnimationSubType::ONLY_TEXT;
+ dump( " paragraph %d,", nPara);
+ dump( " %d characters", end );
+ }
+ }
+ }
+ }
+ break;
+
+ case 2: // sound
+ {
+ OUString aSoundURL( mpPPTImport->ReadSound( nRefId ) );
+ rTarget <<= aSoundURL;
+ dump( " srcRef=\"%s\"", aSoundURL );
+ }
+ break;
+ case 3: // audio object
+ case 4: // video object
+ {
+ SdrObject* pSdrObject = mpPPTImport->getShapeForId( nRefId );
+ if( pSdrObject == nullptr )
+ break;
+
+ rTarget <<= pSdrObject->getUnoShape();
+ }
+ break;
+ default:
+ OSL_FAIL("unknown reference type");
+ }
+
+ }
+ break;
+ case 0x2b01:
+ {
+ sal_Int32 nU1;
+ mrStCtrl.ReadInt32( nU1 );
+ }
+ break;
+ default:
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importTargetElementContainer()!");
+ break;
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+
+ }
+}
+
+void AnimationImporter::importPropertySetContainer( const Atom* pAtom, PropertySet& rSet )
+{
+ DBG_ASSERT( pAtom && (pAtom->getType() == DFF_msofbtAnimPropertySet), "invalid call to ppt::AnimationImporter::importPropertySetContainer()!" );
+
+ if( !pAtom )
+ return;
+
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom )
+ {
+ if( pChildAtom->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ Any aAny;
+ (void)importAttributeValue( pChildAtom, aAny );
+ rSet.maProperties[ pChildAtom->getInstance() ] = aAny;
+ }
+ else
+ {
+ OSL_FAIL("unknown atom inside ppt::AnimationImporter::importPropertySetContainer()!");
+ }
+
+ pChildAtom = Atom::findNextChildAtom( pChildAtom );
+ }
+}
+
+#ifdef DBG_ANIM_LOG
+void AnimationImporter::dump_atom_header( const Atom* pAtom, bool bOpen, bool bAppend )
+{
+ if( pAtom )
+ {
+ const char* pTitle;
+
+ switch( pAtom->getType() )
+ {
+ case DFF_msofbtAnimEvent: pTitle = "AnimEvent"; break;
+ case DFF_msofbtAnimTrigger: pTitle = "AnimTrigger"; break;
+ case DFF_msofbtAnimateMotion: pTitle = "AnimateMotion"; break;
+ case DFF_msofbtAnimPropertySet: pTitle = "AnimPropertySet"; break;
+ case DFF_msofbtAnimateAttributeNames: pTitle = "AnimAttributeName"; break;
+ case DFF_msofbtAnimAttributeValue: pTitle = "AnimAttributeValue"; break;
+ case DFF_msofbtAnimGroup: pTitle = "AnimGroup"; break;
+ case DFF_msofbtAnimNode: pTitle = "AnimNode"; break;
+ case DFF_msofbtAnimValue: pTitle = "AnimValue"; break;
+ case DFF_msofbtAnimateFilter: pTitle = "animateFilter"; break;
+ case DFF_msofbtAnimate: pTitle = "animate"; break;
+ case DFF_msofbtAnimateSet: pTitle = "set"; break;
+ case DFF_msofbtAnimKeyTime: pTitle = "AnimKeyTime"; break;
+ case DFF_msofbtAnimKeyPoints: pTitle = "AnimKeyPoints"; break;
+ case DFF_msofbtAnimReference: pTitle = "AnimReference"; break;
+ case DFF_msofbtAnimateTargetElement: pTitle = "AnimTargetElementContainer"; break;
+ case DFF_msofbtAnimAction: pTitle = "AnimAction"; break;
+ case DFF_msofbtAnimCommand: pTitle = "AnimCommand"; break;
+ case DFF_msofbtAnimateTarget: pTitle = "TransformationTarget"; break;
+ case DFF_msofbtAnimateTargetSettings: pTitle = "TransformationTargetSettings"; break;
+ case DFF_msofbtAnimIteration: pTitle = "iterate"; break;
+ case DFF_msofbtAnimateColorData: pTitle = "colorData"; break;
+ case DFF_msofbtAnimateScaleData: pTitle = "scaleData"; break;
+ case DFF_msofbtAnimateSetData: pTitle = "setData"; break;
+
+ default:
+ {
+ static char buffer[128];
+ sprintf( buffer, "unknown_%#x", pAtom->getType() );
+ pTitle = buffer;
+ }
+ }
+
+ if( bOpen )
+ {
+ fprintf(mpFile, "<%s", pTitle );
+
+ fprintf(mpFile, " instance=\"%hu\"%s",
+ pAtom->getInstance(),
+ bAppend ? "" : ">\n");
+ }
+ else
+ {
+ if( bAppend )
+ fprintf(mpFile,"/>\n");
+ else
+ fprintf(mpFile, "</%s>\n", pTitle );
+ }
+ }
+}
+
+void AnimationImporter::dump( sal_uInt32 nLen, bool bNewLine )
+{
+ char * faul = "0123456789abcdef";
+
+ sal_uInt32 i = 0;
+ int b = 0;
+ char nData;
+
+ for( i = 0; i < nLen; i++ )
+ {
+ mrStCtrl.ReadChar(nData);
+
+ fprintf( mpFile, "%c%c ", faul[ (nData >> 4) & 0x0f ], faul[ nData & 0x0f ] );
+
+ b++;
+ if( bNewLine && (b == 32) )
+ {
+ fprintf(mpFile,"\n");
+ b = 0;
+ }
+ }
+ if( (b != 0) && bNewLine )
+ fprintf(mpFile,"\n");
+}
+
+void AnimationImporter::dump_atom( const Atom* pAtom, bool bNewLine )
+{
+ if( pAtom )
+ {
+ if( pAtom->isContainer() )
+ {
+ const Atom* pChildAtom = pAtom->findFirstChildAtom();
+ while( pChildAtom )
+ {
+ if( pChildAtom->getType() == DFF_msofbtAnimAttributeValue )
+ {
+ fprintf(mpFile, "<attributeValue instance=\"%hu\"", pChildAtom->getInstance() );
+
+ Any aValue;
+ if( importAttributeValue( pChildAtom, aValue ) )
+ {
+ sal_Int32 nInt;
+ OUString aString;
+ double fDouble;
+
+ if( aValue >>= nInt )
+ {
+ fprintf(mpFile, " value=\"%" SAL_PRIdINT32 "\"", nInt );
+ }
+ else if( aValue >>= aString )
+ {
+ fprintf(mpFile, " value=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr());
+ }
+ else if( aValue >>= fDouble )
+ {
+ fprintf(mpFile, " value=\"%g\"", fDouble );
+ }
+ }
+ else
+ {
+ if( pChildAtom->seekToContent() )
+ {
+ fprintf(mpFile, " value=\"" );
+ dump_atom( pChildAtom, false );
+ fprintf(mpFile, "\"");
+ }
+ }
+
+ fprintf(mpFile, "/>\n" );
+ }
+ else
+ {
+ dump_atom_header( pChildAtom, true, pChildAtom->getType() == DFF_msofbtAnimAttributeValue );
+ dump_atom( pChildAtom );
+ dump_atom_header( pChildAtom, false, pChildAtom->getType() == DFF_msofbtAnimAttributeValue );
+ }
+
+ pChildAtom = Atom::findNextChildAtom(pChildAtom);
+ }
+ }
+ else if( pAtom->seekToContent() )
+ {
+ dump( pAtom->getLength(), bNewLine );
+ }
+ }
+}
+
+void AnimationImporter::dump_anim_group( const Atom* pAtom, const AnimationNode& rNode, const PropertySet& rSet, bool bOpen )
+{
+ fprintf( mpFile, bOpen ? "<" : "</" );
+
+ switch( rNode.mnGroupType )
+ {
+ case mso_Anim_GroupType_PAR:
+ fprintf( mpFile, "par" );
+ break;
+ case mso_Anim_GroupType_SEQ:
+ fprintf( mpFile, "seq" );
+ break;
+ case mso_Anim_GroupType_NODE:
+ switch( rNode.mnNodeType )
+ {
+ case mso_Anim_Behaviour_FILTER:
+ fprintf( mpFile, "animateFilter" );
+ break;
+ case mso_Anim_Behaviour_ANIMATION:
+ if( pAtom->hasChildAtom( DFF_msofbtAnimateSet ) )
+ fprintf( mpFile, "set" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateColor ) )
+ fprintf( mpFile, "animateColor" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateScale ) )
+ fprintf( mpFile, "animateScale" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateRotation ) )
+ fprintf( mpFile, "animateRotation" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimateMotion ) )
+ fprintf( mpFile, "animateMotion" );
+ else if( pAtom->hasChildAtom( DFF_msofbtAnimCommand ) )
+ fprintf( mpFile, "command" );
+ else
+ fprintf( mpFile, "animation" );
+ break;
+ default:
+ {
+ fprintf( mpFile, "unknown_node_%#lx", rNode.mnNodeType );
+ }
+ break;
+ }
+ break;
+ case mso_Anim_GroupType_MEDIA:
+ fprintf( mpFile, "media" );
+ break;
+ default:
+ fprintf( mpFile, "unknown_group_%#lx", rNode.mnGroupType );
+ break;
+ }
+
+ if( bOpen )
+ {
+ dump( rNode );
+ dump( rSet );
+ }
+
+ fprintf(mpFile,">\n");
+}
+
+void AnimationImporter::dump( const AnimationNode& rNode )
+{
+ // dump animation node
+ if( rNode.mnRestart != 0 )
+ {
+ fprintf(mpFile," restart=\"%s\"",
+ rNode.mnRestart == 1 ? "always" : (rNode.mnRestart == 2 ? "whenOff" : (rNode.mnRestart == 3 ? "never" : "unknown")) );
+ }
+
+ if( rNode.mnFill )
+ {
+ fprintf(mpFile," fill=\"%s\"",
+ rNode.mnFill == 1 ? "remove" : (rNode.mnFill == 3 ? "hold" : (rNode.mnFill == 2 ? "freeze" : "unknown")) );
+ }
+
+ if( rNode.mnDuration > 0 )
+ {
+ double fSeconds = rNode.mnDuration;
+ fSeconds /= 1000.0;
+ fprintf(mpFile, " dur=\"%g\"", fSeconds);
+ }
+ else if( rNode.mnDuration < 0 )
+ {
+ fprintf(mpFile, " dur=\"indefinite\"" );
+ }
+
+ if( rNode.mnU1 ) fprintf(mpFile," u1=\"%#lx\"", rNode.mnU1);
+ if( rNode.mnU3 ) fprintf(mpFile," u3=\"%#lx\"", rNode.mnU3);
+ if( rNode.mnU4 ) fprintf(mpFile," u4=\"%#lx\"", rNode.mnU4);
+}
+
+void AnimationImporter::dump( Any& rAny )
+{
+ Sequence< Any > aSeq;
+ sal_Int32 nInt;
+ double fDouble;
+ OUString aString;
+ sal_Bool bBool;
+ Event aEvent;
+ Timing aTiming;
+
+ if( rAny >>= aSeq )
+ {
+ const sal_Int32 nSize = aSeq.getLength();
+ sal_Int32 nIndex = 0;
+ while( nIndex < nSize )
+ {
+ dump( aSeq[nIndex++] );
+ if(nIndex < nSize)
+ fprintf( mpFile, "," );
+ }
+ }
+ else if( rAny >>= aString )
+ {
+ fprintf( mpFile, "%s", OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ }
+ else if( rAny >>= nInt )
+ {
+ fprintf( mpFile, "%" SAL_PRIdINT32, nInt );
+ }
+ else if( rAny >>= bBool )
+ {
+ fprintf( mpFile, "%s", bBool ? "true" : "false" );
+ }
+ else if( rAny >>= fDouble )
+ {
+ fprintf( mpFile, "%g", fDouble );
+ }
+ else if( rAny >>= aTiming )
+ {
+ fprintf( mpFile, "%s", aTiming == (Timing_INDEFINITE) ? "indefinite" : "media" );
+ }
+ else if( rAny >>= aEvent )
+ {
+ if( aEvent.Trigger != EventTrigger::NONE )
+ {
+ static const char* triggers[] =
+ {
+ "none","onbegin","onend","begin",
+ "end","onclick","ondoubleclick","onmouseenter",
+ "onmouseleave","onpptnext","onpptprev","onstopaudio"
+ };
+
+ if( aEvent.Source.hasValue() )
+ {
+ dump_target( aEvent.Source );
+ dump( "." );
+ }
+
+ dump( triggers[ aEvent.Trigger ] );
+ }
+
+ if( aEvent.Offset.hasValue() )
+ {
+ double fOffset;
+ if( aEvent.Offset >>= fOffset )
+ fprintf( mpFile, "%g", fOffset );
+ else
+ dump( "indefinite" );
+ }
+ }
+}
+
+void AnimationImporter::dump( const PropertySet& rSet )
+{
+ // dump property set
+
+ for( const auto& rProp : rSet.maProperties )
+ {
+ bool bKnown = false;
+
+ const sal_Int32 nInstance = rProp.first;
+ Any aAny( rProp.second );
+
+ switch ( nInstance )
+ {
+ case DFF_ANIM_COLORSPACE:
+ {
+ sal_Int32 nColorSpace;
+ if( aAny >>= nColorSpace )
+ {
+ fprintf( mpFile, " colorSpace=\"%s\"", (nColorSpace == 0) ? "rgb" : (nColorSpace == 1) ? "hsl" : "unknown" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_DIRECTION:
+ {
+ sal_Bool bDirection;
+ if( aAny >>= bDirection )
+ {
+ fprintf( mpFile, " direction=\"%s\"", bDirection ? "cclockwise" : "clockwise" );
+ bKnown = true;
+ }
+ else
+ {
+ sal_Int32 nMasterRel;
+ if( aAny >>= nMasterRel )
+ {
+ fprintf( mpFile, " direction=\"%s\"", nMasterRel == 0 ? "sameClick" : ( nMasterRel == 2 ? "nextClick" : "lastClick" ) );
+ bKnown = true;
+ }
+ }
+ }
+ break;
+
+ case DFF_ANIM_OVERRIDE: // TODO
+ {
+ sal_Int32 nOverride;
+ if( aAny >>= nOverride )
+ {
+ fprintf( mpFile, " override=\"%s\"", (nOverride == 1) ? "childStyle" : (nOverride == 0) ? "normal" : "unknown" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PATH_EDIT_MODE:
+ {
+ sal_Bool bPathEditMode;
+ if( aAny >>= bPathEditMode )
+ {
+ fprintf( mpFile, " pptPathEditMode=\"%s\"", bPathEditMode ? "relative" : "fixed" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_ID :
+ {
+ sal_Int32 nPresetId ;
+ if( aAny >>= nPresetId )
+ {
+ fprintf(mpFile, " presetid=\"%" SAL_PRIdINT32 "\"", nPresetId );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_SUB_TYPE :
+ {
+ sal_Int32 nPointsType ;
+ if( aAny >>= nPointsType )
+ {
+ fprintf(mpFile, " presetSubType=\"%" SAL_PRIdINT32 "\"", nPointsType );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_PRESET_CLASS :
+ {
+ sal_Int32 nPresetClass;
+ if ( aAny >>= nPresetClass )
+ {
+ const char* pMode;
+ switch( nPresetClass )
+ {
+ case DFF_ANIM_PRESS_CLASS_USER_DEFINED: pMode = "userdefined"; break;
+ case DFF_ANIM_PRESS_CLASS_ENTRANCE: pMode = "entrance"; break;
+ case DFF_ANIM_PRESS_CLASS_EXIT: pMode = "exit"; break;
+ case DFF_ANIM_PRESS_CLASS_EMPHASIS: pMode = "emphasis"; break;
+ case DFF_ANIM_PRESS_CLASS_MOTIONPATH: pMode = "motionpath"; break;
+ case DFF_ANIM_PRESS_CLASS_OLE_ACTION: pMode = "oleaction"; break;
+ case DFF_ANIM_PRESS_CLASS_MEDIACALL: pMode = "mediacall"; break;
+ default:
+ pMode = nullptr;
+ break;
+ }
+
+ if (pMode)
+ fprintf(mpFile, " class=\"%s\"", pMode);
+ else
+ fprintf(mpFile, " class =\"%" SAL_PRIdINT32 "\"", nPresetClass);
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_NODE_TYPE :
+ {
+ sal_Int32 nNodeType;
+ if ( aAny >>= nNodeType )
+ {
+ const char* pNode;
+ switch( nNodeType )
+ {
+ case DFF_ANIM_NODE_TYPE_ON_CLICK: pNode = "onclick"; break;
+ case DFF_ANIM_NODE_TYPE_WITH_PREVIOUS: pNode = "withprevious"; break;
+ case DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS: pNode = "afterprevious"; break;
+ case DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE: pNode = "mainsequence"; break;
+ case DFF_ANIM_NODE_TYPE_TIMING_ROOT: pNode = "timingroot"; break;
+ case DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ:pNode = "interactivesequence"; break;
+ default :
+ {
+ static char buffer[128];
+ sprintf( buffer, "%" SAL_PRIdINT32, nNodeType );
+ pNode = buffer;
+ }
+ break;
+ }
+
+ fprintf(mpFile, " nodeType=\"%s\"", pNode);
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_GROUP_ID:
+ {
+ sal_Int32 nGroupId;
+ if ( aAny >>= nGroupId )
+ {
+ fprintf( mpFile, " groupId=\"%" SAL_PRIdINT32 "\"", nGroupId );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_ID:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " id=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_EVENT_FILTER:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " eventFilter=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_ENDAFTERSLIDE:
+ {
+ sal_Int32 nEndAfterSlide;
+ if( aAny >>= nEndAfterSlide )
+ {
+ fprintf(mpFile, " endAfterSlide=\"%" SAL_PRIdINT32 "\"", nEndAfterSlide );
+ bKnown = true;
+ }
+ }
+
+ case DFF_ANIM_TIMEFILTER:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " timeFilter=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_RUNTIMECONTEXT:
+ {
+ OUString aString;
+ if( aAny >>= aString )
+ {
+ fprintf( mpFile, " runtimeContext=\"%s\"",
+ OUStringToOString(aString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_VOLUME:
+ {
+ double fVolume(0.0);
+ if( aAny >>= fVolume )
+ {
+ fprintf( mpFile, " volume=\"%g%%\"", (double)(fVolume * 100.0) );
+ bKnown = true;
+ }
+ }
+ break;
+
+ case DFF_ANIM_AFTEREFFECT:
+ {
+ sal_Bool bAfterEffect;
+ if( aAny >>= bAfterEffect )
+ {
+ fprintf( mpFile, "afterEffect=\"%s\"", bAfterEffect ? "true" : "false" );
+ bKnown = true;
+ }
+ }
+ break;
+
+ }
+
+ if( !bKnown )
+ {
+ fprintf( mpFile, " unknown_%" SAL_PRIdINT32 "=\"", nInstance );
+ dump( aAny );
+ fprintf( mpFile, "\"" );
+ }
+ }
+}
+
+void AnimationImporter::dump_target( Any& rAny )
+{
+ Any aSource, aSourceData;
+ Sequence< Any > aSeq;
+ if( rAny >>= aSeq )
+ {
+ if( aSeq.getLength() >= 1 ) aSource = aSeq[0];
+ if( aSeq.getLength() >= 2 ) aSourceData = aSeq[1];
+ }
+ else
+ {
+ aSource = rAny;
+ }
+
+ Reference< XShape > xShape;
+ aSource >>= xShape;
+ if( xShape.is() )
+ {
+ OUString aStr( xShape->getShapeType() );
+ dump( aStr );
+
+ if( aSourceData.hasValue() )
+ {
+ dump( "(" );
+ dump( aSourceData );
+ dump( ")" );
+ }
+ }
+}
+
+void AnimationImporter::dump( const char * pText )
+{
+ fprintf( mpFile, "%s", pText );
+}
+
+void AnimationImporter::dump( const OUString& rString )
+{
+ fprintf( mpFile, OUStringToOString(rString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+}
+
+void AnimationImporter::dump( const char * pText, sal_Int64 nInt )
+{
+ fprintf( mpFile, pText, nInt );
+}
+
+void AnimationImporter::dump( const char * pText, sal_Int32 nInt )
+{
+ fprintf( mpFile, pText, nInt );
+}
+
+void AnimationImporter::dump( const char * pText, double fDouble )
+{
+ fprintf( mpFile, pText, fDouble );
+}
+
+void AnimationImporter::dump( const char * pText, const char * pText2 )
+{
+ fprintf( mpFile, pText, pText2 );
+}
+
+void AnimationImporter::dump( const char * pText, const OUString& rString )
+{
+ fprintf( mpFile, pText, OUStringToOString(rString,
+ RTL_TEXTENCODING_UTF8).getStr() );
+}
+
+#else
+
+void AnimationImporter::dump_atom_header( const Atom* , bool , bool )
+{
+}
+
+void AnimationImporter::dump_atom( const Atom* , bool )
+{
+}
+
+void AnimationImporter::dump_target( css::uno::Any& )
+{
+}
+
+void AnimationImporter::dump( css::uno::Any& )
+{
+}
+
+void AnimationImporter::dump( const PropertySet& )
+{
+}
+
+void AnimationImporter::dump( const AnimationNode& )
+{
+}
+
+void AnimationImporter::dump( const char * )
+{
+}
+
+void AnimationImporter::dump( const char * , sal_Int32 )
+{
+}
+
+void AnimationImporter::dump( const char * , double )
+{
+}
+
+void AnimationImporter::dump( const char * , const char * )
+{
+}
+
+void AnimationImporter::dump( const char * , std::u16string_view )
+{
+}
+
+#endif
+
+} // namespace ppt;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */