diff options
Diffstat (limited to 'sd/source/filter/eppt/pptexanimations.cxx')
-rw-r--r-- | sd/source/filter/eppt/pptexanimations.cxx | 2191 |
1 files changed, 2191 insertions, 0 deletions
diff --git a/sd/source/filter/eppt/pptexanimations.cxx b/sd/source/filter/eppt/pptexanimations.cxx new file mode 100644 index 000000000000..4e4b50007443 --- /dev/null +++ b/sd/source/filter/eppt/pptexanimations.cxx @@ -0,0 +1,2191 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sd.hxx" +#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/EventTrigger.hpp> +#include <com/sun/star/presentation/EffectNodeType.hpp> +#include <com/sun/star/presentation/EffectPresetClass.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/util/XCloneable.hpp> +#include <com/sun/star/animations/AnimationAdditiveMode.hpp> +#include <com/sun/star/animations/XAnimateSet.hpp> +#include <com/sun/star/animations/XAudio.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/TransitionType.hpp> +#include <com/sun/star/animations/TransitionSubType.hpp> +#include <com/sun/star/animations/ValuePair.hpp> +#include <com/sun/star/animations/AnimationColorSpace.hpp> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <com/sun/star/awt/FontWeight.hpp> +#include <com/sun/star/awt/FontUnderline.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/text/XSimpleText.hpp> +#include <com/sun/star/animations/XIterateContainer.hpp> +#include <com/sun/star/presentation/TextAnimationType.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <comphelper/processfactory.hxx> +#include <rtl/ustrbuf.hxx> +#ifndef _RTL_MEMORY_H_ +#include <rtl/memory.hxx> +#endif + +#include <vcl/vclenum.hxx> +#include <svx/svdotext.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/editobj.hxx> +#include <pptexanimations.hxx> +#include <osl/endian.h> + +#include <algorithm> + +using ::std::map; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::com::sun::star::uno::Any; +using ::com::sun::star::container::XChild; +using ::com::sun::star::util::XCloneable; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::uno::Sequence; +using ::com::sun::star::uno::makeAny; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::XInterface; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::lang::XMultiServiceFactory; + +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; + +namespace ppt +{ + +void ImplTranslateAttribute( rtl::OUString& rString, const TranslateMode eTranslateMode ) +{ + if ( eTranslateMode != TRANSLATE_NONE ) + { + if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) ) + { + const ImplAttributeNameConversion* p = gImplConversionList; + while( p->mpAPIName ) + { + if( rString.compareToAscii( p->mpAPIName ) == 0 ) + break; + p++; + } + if( p->mpMSName ) + { + if ( eTranslateMode & TRANSLATE_VALUE ) + { + rString = rtl::OUString( (sal_Unicode)'#' ); + rString += OUString::createFromAscii( p->mpMSName ); + } + else + rString = OUString::createFromAscii( p->mpMSName ); + } + } + else if ( eTranslateMode & TRANSLATE_MEASURE ) + { + const sal_Char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", NULL }; + const sal_Char* pSource[] = { "x", "y", "width", "height", NULL }; + sal_Int32 nIndex = 0; + + const sal_Char** ps = pSource; + const sal_Char** pd = pDest; + + while( *ps ) + { + const OUString aSearch( OUString::createFromAscii( *ps ) ); + while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 ) + { + sal_Int32 nLength = aSearch.getLength(); + if( nIndex && (rString.getStr()[nIndex-1] == '#' ) ) + { + nIndex--; + nLength++; + } + + const OUString aNew( OUString::createFromAscii( *pd ) ); + rString = rString.replaceAt( nIndex, nLength, aNew ); + nIndex += aNew.getLength(); + } + ps++; + pd++; + } + } + } +} + +sal_uInt32 ImplTranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, const rtl::OUString& rPresetSubType ) +{ + sal_uInt32 nPresetSubType = 0; + sal_Bool bTranslated = sal_False; + + if ( ( nPresetClass == (sal_uInt32)EffectPresetClass::ENTRANCE ) || ( nPresetClass == (sal_uInt32)EffectPresetClass::EXIT ) ) + { + if ( nPresetId != 21 ) + { + switch( nPresetId ) + { + case 5 : + { + if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "downward" ) ) ) + { + nPresetSubType = 5; + bTranslated = sal_True; + } + else if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "across" ) ) ) + { + nPresetSubType = 10; + bTranslated = sal_True; + } + } + break; + case 17 : + { + if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "across" ) ) ) + { + nPresetSubType = 10; + bTranslated = sal_True; + } + } + break; + case 18 : + { + if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "right-to-top" ) ) ) + { + nPresetSubType = 3; + bTranslated = sal_True; + } + else if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "right-to-bottom" ) ) ) + { + nPresetSubType = 6; + bTranslated = sal_True; + } + else if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "left-to-top" ) ) ) + { + nPresetSubType = 9; + bTranslated = sal_True; + } + else if ( rPresetSubType.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "left-to-bottom" ) ) ) + { + nPresetSubType = 12; + bTranslated = sal_True; + } + } + break; + } + } + if ( !bTranslated ) + { + const convert_subtype* p = gConvertArray; + while( p->mpStrSubType ) + { + if ( rPresetSubType.equalsAscii( p->mpStrSubType ) ) + { + nPresetSubType = p->mnID; + bTranslated = sal_True; + break; + } + p++; + } + } + } + if ( !bTranslated ) + nPresetSubType = (sal_uInt32)rPresetSubType.toInt32(); + return nPresetSubType; +} + +const sal_Char* transition::find( const sal_Int16 nType, const sal_Int16 nSubType, const sal_Bool bDirection ) +{ + const sal_Char* pRet = NULL; + int nFit = 0; + + const transition* p = gTransitions; + while( p->mpName ) + { + int nF = 0; + if ( nType == p->mnType ) + nF += 4; + if ( nSubType == p->mnSubType ) + nF += 2; + if ( bDirection == p->mbDirection ) + nF += 1; + if ( nF > nFit ) + { + pRet = p->mpName; + nFit = nF; + } + if ( nFit == 7 ) // maximum + break; + p++; + } + return pRet; +} + +SvStream& operator<<(SvStream& rOut, AnimationNode& rNode ) +{ + rOut << rNode.mnU1; + rOut << rNode.mnRestart; + rOut << rNode.mnGroupType; + rOut << rNode.mnFill; + rOut << rNode.mnU3; + rOut << rNode.mnU4; + rOut << rNode.mnDuration; + rOut << rNode.mnNodeType; + + return rOut; +} + +AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) : + mrSolverContainer ( rSolverContainer ), + mrExSoundCollection ( rExSoundCollection ), + mnCurrentGroup(0) +{ +} + +// -------------------------------------------------------------------- + +static sal_Int16 GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault ) +{ + sal_Int16 nFill = xNode->getFill(); + if ( ( nFill == AnimationFill::DEFAULT ) || + ( nFill == AnimationFill::INHERIT ) ) + { + if ( nFill != AnimationFill::AUTO ) + nFill = nFillDefault; + } + if( nFill == AnimationFill::AUTO ) + { + nFill = AnimationFill::REMOVE; + sal_Bool bIsIndefiniteTiming = sal_True; + Any aAny = xNode->getDuration(); + if( aAny.hasValue() ) + { + Timing eTiming; + if( aAny >>= eTiming ) + bIsIndefiniteTiming = eTiming == Timing_INDEFINITE; + } + if ( bIsIndefiniteTiming ) + { + aAny = xNode->getEnd(); + if( aAny.hasValue() ) + { + Timing eTiming; + if( aAny >>= eTiming ) + bIsIndefiniteTiming = eTiming == Timing_INDEFINITE; + } + if ( bIsIndefiniteTiming ) + { + if ( !xNode->getRepeatCount().hasValue() ) + { + aAny = xNode->getRepeatDuration(); + if( aAny.hasValue() ) + { + Timing eTiming; + if( aAny >>= eTiming ) + bIsIndefiniteTiming = eTiming == Timing_INDEFINITE; + } + if ( bIsIndefiniteTiming ) + nFill = AnimationFill::FREEZE; + } + } + } + } + return nFill; +} + +void AnimationExporter::doexport( const Reference< XDrawPage >& xPage, SvStream& rStrm ) +{ + Reference< XAnimationNodeSupplier > xNodeSupplier( xPage, UNO_QUERY ); + if( xNodeSupplier.is() ) + { + const Reference< XAnimationNode > xRootNode( xNodeSupplier->getAnimationNode() ); + if( xRootNode.is() ) + { + processAfterEffectNodes( xRootNode ); + exportNode( rStrm, xRootNode, NULL, DFF_msofbtAnimGroup, 1, 0, sal_False, AnimationFill::AUTO ); + } + } +} + +void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode ) +{ + try + { + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY_THROW ); + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xEnumerationAccess2( xNode, UNO_QUERY ); + if ( xEnumerationAccess2.is() ) + { + Reference< XEnumeration > xEnumeration2( xEnumerationAccess2->createEnumeration(), UNO_QUERY_THROW ); + while( xEnumeration2->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), UNO_QUERY_THROW ); + while( xEnumeration3->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), UNO_QUERY_THROW ); + while( xEnumeration4->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode3( xEnumeration4->nextElement(), UNO_QUERY_THROW ); + + switch( xChildNode3->getType() ) + { + // found an after effect + case AnimationNodeType::SET: + case AnimationNodeType::ANIMATECOLOR: + { + Reference< XAnimationNode > xMaster; + + Sequence< NamedValue > aUserData( xChildNode3->getUserData() ); + sal_Int32 nLength = aUserData.getLength(); + const NamedValue* p = aUserData.getConstArray(); + + while( nLength-- ) + { + if( p->Name.equalsAscii( "master-element" ) ) + { + p->Value >>= xMaster; + break; + } + p++; + } + + AfterEffectNodePtr pAfterEffectNode( new AfterEffectNode( xChildNode3, xMaster ) ); + maAfterEffectNodes.push_back( pAfterEffectNode ); + } + break; + } + } + } + } + } + } + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR( "(@CL)AnimationExporter::processAfterEffectNodes(), exception cought!" ); + } +} + +bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const +{ + std::list< AfterEffectNodePtr >::const_iterator aIter( maAfterEffectNodes.begin() ); + const std::list< AfterEffectNodePtr >::const_iterator aEnd( maAfterEffectNodes.end() ); + while( aIter != aEnd ) + { + if( (*aIter)->mxNode == xNode ) + return true; + aIter++; + } + + return false; +} + +bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const +{ + std::list< AfterEffectNodePtr >::const_iterator aIter( maAfterEffectNodes.begin() ); + const std::list< AfterEffectNodePtr >::const_iterator aEnd( maAfterEffectNodes.end() ); + while( aIter != aEnd ) + { + if( (*aIter)->mxMaster == xNode ) + { + xAfterEffectNode = (*aIter)->mxNode; + return true; + } + aIter++; + } + + return false; +} + +// check if this group only contain empty groups. this may happen when +// after effect nodes are not exported at theire original position +bool AnimationExporter::isEmptyNode( const Reference< XAnimationNode >& xNode ) const +{ + if( xNode.is() ) switch( xNode->getType() ) + { + case AnimationNodeType::PAR : + case AnimationNodeType::SEQ : + case AnimationNodeType::ITERATE : + { + Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY ); + if( xEnumerationAccess.is() ) + { + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); + if( xEnumeration.is() ) + { + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY ); + if( xChildNode.is() && !isEmptyNode( xChildNode ) ) + return false; + } + } + } + } + break; + + case AnimationNodeType::SET : + case AnimationNodeType::ANIMATECOLOR : + return isAfterEffectNode( xNode ); + default: + return false; + } + + return true; +} + +void AnimationExporter::exportNode( SvStream& rStrm, Reference< XAnimationNode > xNode, const Reference< XAnimationNode >* pParent, const sal_uInt16 nContainerRecType, + const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const sal_Bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef ) +{ + if( (nGroupLevel == 4) && isEmptyNode( xNode ) ) + return; + + if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) ) + return; + + if( nContainerRecType == DFF_msofbtAnimGroup ) + mnCurrentGroup++; + + sal_Bool bTakeBackInteractiveSequenceTimingForChild = sal_False; + sal_Int16 nFillDefault = GetFillMode( xNode, nFDef ); + + bool bSkipChildren = false; + + Reference< XAnimationNode > xAudioNode; + static sal_uInt32 nAudioGroup; + + { + EscherExContainer aContainer( rStrm, nContainerRecType, nInstance ); + switch( xNode->getType() ) + { + case AnimationNodeType::CUSTOM : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + } + break; + + case AnimationNodeType::PAR : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + sal_Int32 nFlags = nGroupLevel == 2 ? 0x10 : 0; + if ( bTakeBackInteractiveSequenceTiming ) + nFlags |= 0x40; + exportAnimEvent( rStrm, xNode, nFlags ); + exportAnimValue( rStrm, xNode, nGroupLevel == 4 ); + } + break; + + case AnimationNodeType::SEQ : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode ); + sal_Int32 nFlags = 12; + if ( ( nGroupLevel == 1 ) && ( nNodeType == ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) ) + { + nFlags |= 0x20; + bTakeBackInteractiveSequenceTimingForChild = sal_True; + } + exportAnimAction( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, nFlags ); + exportAnimValue( rStrm, xNode, sal_False ); + } + break; + + case AnimationNodeType::ITERATE : + { + { + EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode ); + AnimationNode aAnim; + rtl_zeroMemory( &aAnim, sizeof( aAnim ) ); + aAnim.mnGroupType = mso_Anim_GroupType_PAR; + aAnim.mnNodeType = 1; + // attribute Restart + switch( xNode->getRestart() ) + { + default: + case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break; + case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break; + case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break; + case AnimationRestart::NEVER : aAnim.mnRestart = 3; break; + } + // attribute Fill + switch( xNode->getFill() ) + { + default: + case AnimationFill::DEFAULT : aAnim.mnFill = 0; break; + case AnimationFill::REMOVE : aAnim.mnFill = 1; break; + case AnimationFill::FREEZE : aAnim.mnFill = 2; break; + case AnimationFill::HOLD : aAnim.mnFill = 3; break; + case AnimationFill::TRANSITION : aAnim.mnFill = 4; break; + } + rStrm << aAnim; + } + exportIterate( rStrm, xNode ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + + /* + EscherExContainer aContainer( rStrm, DFF_msofbtAnimGroup, 1 ); + exportAnimNode( rStrm, xNode, pParent, nGroupLevel + 1, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + */ + } + break; + + case AnimationNodeType::ANIMATE : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + exportAnimate( rStrm, xNode ); + } + break; + + case AnimationNodeType::SET : + { + bool bIsAfterEffectNode( isAfterEffectNode( xNode ) ); + if( (nGroupLevel != 4) || !bIsAfterEffectNode ) + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + } + else + { + bSkipChildren = true; + } + } + break; + + case AnimationNodeType::ANIMATEMOTION : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimateMotion( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + } + break; + + case AnimationNodeType::ANIMATECOLOR : + { + bool bIsAfterEffectNode( isAfterEffectNode( xNode ) ); + if( (nGroupLevel != 4) || !bIsAfterEffectNode ) + { + if( bIsAfterEffectNode ) + xNode = createAfterEffectNodeClone( xNode ); + + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + } + else + { + bSkipChildren = true; + } + } + break; + + case AnimationNodeType::ANIMATETRANSFORM : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimateTransform( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + } + break; + + case AnimationNodeType::TRANSITIONFILTER : + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + exportAnimEvent( rStrm, xNode, 0 ); + exportAnimValue( rStrm, xNode, sal_False ); + exportTransitionFilter( rStrm, xNode ); + } + break; + + case AnimationNodeType::AUDIO : // #i58428# + { + exportAnimNode( rStrm, xNode, pParent, nGroupLevel, nFillDefault ); + exportAnimPropertySet( rStrm, xNode ); + + Reference< XAudio > xAudio( xNode, UNO_QUERY ); + if( xAudio.is() ) + { + Any aAny( xAudio->getSource() ); + rtl::OUString aURL; + + if ( ( aAny >>= aURL ) && ( aURL.getLength() ) ) + { + sal_Int32 nU1 = 2; + sal_Int32 nTrigger = 3; + sal_Int32 nU3 = nAudioGroup; + sal_Int32 nBegin = 0; + { + EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 1 ); + { + EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger ); + rStrm << nU1 << nTrigger << nU3 << nBegin; + } + } + nU1 = 1; + nTrigger = 0xb; + nU3 = 0; + { + EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 ); + { + EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger ); + rStrm << nU1 << nTrigger << nU3 << nBegin; + } + } + EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement ); + { + sal_uInt32 nRefMode = 3; + sal_uInt32 nRefType = 2; + sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL ); + sal_Int32 begin = -1; + sal_Int32 end = -1; + + EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference ); + rStrm << nRefMode << nRefType << nRefId << begin << end; + } + } + } + exportAnimValue( rStrm, xNode, sal_False ); + } + break; + } + if( !bSkipChildren ) + { + // export after effect node if one exists for this node + Reference< XAnimationNode > xAfterEffectNode; + if( hasAfterEffectNode( xNode, xAfterEffectNode ) ) + { + exportNode( rStrm, xAfterEffectNode, &xNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault ); + } + + Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY ); + if( xEnumerationAccess.is() ) + { + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); + if( xEnumeration.is() ) + { + while( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY ); + if( xChildNode.is() ) + { + if ( xChildNode->getType() == AnimationNodeType::AUDIO ) + { + xAudioNode = xChildNode; + nAudioGroup = mnCurrentGroup; + } + else + exportNode( rStrm, xChildNode, &xNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault ); + } + } + } + } + } + } + if ( xAudioNode.is() ) + exportNode( rStrm, xAudioNode, &xNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault ); + + if( xNode->getType() == AnimationNodeType::ITERATE ) + aTarget = Any(); +} + +Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode ) const +{ + try + { + Reference< ::com::sun::star::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW ); + Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW ); + + Any aEmpty; + xCloneNode->setBegin( aEmpty ); + + + return xCloneNode; + } + catch( Exception& e ) + { + (void)e; + DBG_ERROR("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" ); + } + return xNode; +} + +void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode, + const ::com::sun::star::uno::Reference< ::com::sun::star::animations::XAnimationNode >*, const sal_Int32, const sal_Int16 nFillDefault ) +{ + EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode ); + AnimationNode aAnim; + rtl_zeroMemory( &aAnim, sizeof( aAnim ) ); + + // attribute Restart + switch( xNode->getRestart() ) + { + default: + case AnimationRestart::DEFAULT : aAnim.mnRestart = 0; break; + case AnimationRestart::ALWAYS : aAnim.mnRestart = 1; break; + case AnimationRestart::WHEN_NOT_ACTIVE : aAnim.mnRestart = 2; break; + case AnimationRestart::NEVER : aAnim.mnRestart = 3; break; + } + + // attribute Fill +// aAnim.mnFill = GetFillMode( xNode, pParent ); + switch( nFillDefault ) + { + default: + case AnimationFill::DEFAULT : aAnim.mnFill = 0; break; + case AnimationFill::REMOVE : aAnim.mnFill = 1; break; + case AnimationFill::FREEZE : // aAnim.mnFill = 2; break; + case AnimationFill::HOLD : aAnim.mnFill = 3; break; + case AnimationFill::TRANSITION : aAnim.mnFill = 4; break; + } + // attribute Duration + double fDuration = 0.0; + com::sun::star::animations::Timing eTiming; + if ( xNode->getDuration() >>= eTiming ) + { + if ( eTiming == Timing_INDEFINITE ) + aAnim.mnDuration = -1; + } + else if ( xNode->getDuration() >>= fDuration ) + { + aAnim.mnDuration = (sal_Int32)( fDuration * 1000.0 ); + } + else + aAnim.mnDuration = -1; + + // NodeType, NodeGroup + aAnim.mnNodeType = 1; + aAnim.mnGroupType = mso_Anim_GroupType_SEQ; + switch( xNode->getType() ) + { + case AnimationNodeType::PAR : // PASSTROUGH!!! (as it was intended) + aAnim.mnGroupType = mso_Anim_GroupType_PAR; + case AnimationNodeType::SEQ : + { + // trying to get the nodetype + Sequence< NamedValue > aUserData = xNode->getUserData(); + if ( aUserData.getLength() ) + { + const NamedValue* p = aUserData.getConstArray(); + sal_Int32 nLength = aUserData.getLength(); + while( nLength-- ) + { + if( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "node-type" ) ) ) + { + sal_Int16 nType = 0; + if ( p->Value >>= nType ) + { + switch( nType ) + { + case ::com::sun::star::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break; + case ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; break; + /* + case ::com::sun::star::presentation::EffectNodeType::ON_CLICK : + case ::com::sun::star::presentation::EffectNodeType::WITH_PREVIOUS : + case ::com::sun::star::presentation::EffectNodeType::AFTER_PREVIOUS : + case ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE : + default: + */ + } + } + break; + } + } + } + } + break; + + case AnimationNodeType::ANIMATE : + case AnimationNodeType::SET : + + case AnimationNodeType::CUSTOM : + case AnimationNodeType::ITERATE : + case AnimationNodeType::ANIMATEMOTION : + case AnimationNodeType::ANIMATECOLOR : + case AnimationNodeType::ANIMATETRANSFORM : + { + aAnim.mnGroupType = mso_Anim_GroupType_NODE; + aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION; + } + break; + + case AnimationNodeType::AUDIO : + { + aAnim.mnGroupType = mso_Anim_GroupType_MEDIA; + aAnim.mnNodeType = mso_Anim_Behaviour_ANIMATION; + } + break; + + case AnimationNodeType::TRANSITIONFILTER : + { + aAnim.mnGroupType = mso_Anim_GroupType_NODE; + aAnim.mnNodeType = mso_Anim_Behaviour_FILTER; + } + break; + } + rStrm << aAnim; +} + +sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + sal_Int16 nNodeType = ::com::sun::star::presentation::EffectNodeType::DEFAULT; + + EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet ); + const ::com::sun::star::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ]; + rtl_zeroMemory( pAny, sizeof( pAny ) ); + + Reference< XAnimationNode > xMaster; + + const Any aTrue( makeAny( (sal_Bool)sal_True ) ); + Any aMasterRel, aOverride, aRunTimeContext; + + // storing user data into pAny, to allow direct access later + Sequence< NamedValue > aUserData = xNode->getUserData(); + if ( aUserData.getLength() ) + { + const NamedValue* p = aUserData.getConstArray(); + sal_Int32 nLength = aUserData.getLength(); + while( nLength-- ) + { + if( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "node-type" ) ) ) + { + pAny[ DFF_ANIM_NODE_TYPE ] = &(p->Value); + } + else if ( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-class" ) ) ) + { + pAny[ DFF_ANIM_PRESET_CLASS ] = &(p->Value); + } + else if ( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-id" ) ) ) + { + pAny[ DFF_ANIM_PRESET_ID ] = &(p->Value); + } + else if ( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "preset-sub-type" ) ) ) + { + pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(p->Value); + } + else if ( p->Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "master-element" ) ) ) + { + pAny[ DFF_ANIM_AFTEREFFECT ] = &aTrue; + p->Value >>= xMaster; + } + p++; + } + } + + // calculate master-rel + if( xMaster.is() ) + { + sal_Int32 nMasterRel = 2; + Reference< XChild > xNodeChild( xNode, UNO_QUERY ); + Reference< XChild > xMasterChild( xMaster, UNO_QUERY ); + if( xNodeChild.is() && xMasterChild.is() && (xNodeChild->getParent() == xMasterChild->getParent() ) ) + nMasterRel = 0; + + aMasterRel <<= nMasterRel; + + pAny[ DFF_ANIM_MASTERREL ] = &aMasterRel; + + aOverride <<= (sal_Int32)1; + pAny[ DFF_ANIM_OVERRIDE ] = &aOverride; + + aRunTimeContext <<= (sal_Int32)1; + pAny[ DFF_ANIM_RUNTIMECONTEXT ] = &aRunTimeContext; + } + + // the order is important + if ( pAny[ DFF_ANIM_NODE_TYPE ] ) + { + if ( *pAny[ DFF_ANIM_NODE_TYPE ] >>= nNodeType ) + { + sal_uInt32 nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; + switch( nNodeType ) + { + case ::com::sun::star::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break; + case ::com::sun::star::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break; + case ::com::sun::star::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break; + case ::com::sun::star::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break; + case ::com::sun::star::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break; + case ::com::sun::star::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break; + } + exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType, TRANSLATE_NONE ); + } + } + sal_uInt32 nPresetId = 0; + sal_uInt32 nPresetSubType = 0; + sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM; + sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED; + sal_Bool bPresetClass, bPresetId, bPresetSubType; + bPresetClass = bPresetId = bPresetSubType = sal_False; + + if ( pAny[ DFF_ANIM_PRESET_CLASS ] ) + { + if ( *pAny[ DFF_ANIM_PRESET_CLASS ] >>= nAPIPresetClass ) + { + sal_uInt8 nPPTPresetClass; + switch( nAPIPresetClass ) + { + case EffectPresetClass::ENTRANCE : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_ENTRANCE; break; + case EffectPresetClass::EXIT : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EXIT; break; + case EffectPresetClass::EMPHASIS : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_EMPHASIS; break; + case EffectPresetClass::MOTIONPATH : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MOTIONPATH; break; + case EffectPresetClass::OLEACTION : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_OLE_ACTION; break; + case EffectPresetClass::MEDIACALL : nPPTPresetClass = DFF_ANIM_PRESS_CLASS_MEDIACALL; break; + default : + nPPTPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED; + } + nPresetClass = nPPTPresetClass; + bPresetClass = sal_True; + } + } + if ( pAny[ DFF_ANIM_PRESET_ID ] ) + { + rtl::OUString sPreset; + if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset ) + { + if ( sPreset.match( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ppt_" ) ), 0 ) ) + { + sal_Int32 nLast = sPreset.lastIndexOf( '_' ); + if ( ( nLast != -1 ) && ( ( nLast + 1 ) < sPreset.getLength() ) ) + { + rtl::OUString aNumber( sPreset.copy( nLast + 1 ) ); + nPresetId = aNumber.toInt32(); + bPresetId = sal_True; + } + } + else + { + const preset_maping* p = gPresetMaping; + while( p->mpStrPresetId && ((p->mnPresetClass != (sal_Int32)nAPIPresetClass) || !sPreset.equalsAscii( p->mpStrPresetId )) ) + p++; + + if( p->mpStrPresetId ) + { + nPresetId = p->mnPresetId; + bPresetId = sal_True; + } + } + } + } + + if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] ) + { + rtl::OUString sPresetSubType; + if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType ) + { + nPresetSubType = ImplTranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType ); + bPresetSubType = sal_True; + } + } + if ( bPresetId ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId, TRANSLATE_NONE ); + if ( bPresetSubType ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType, TRANSLATE_NONE ); + if ( bPresetClass ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass, TRANSLATE_NONE ); + + if ( pAny[ DFF_ANIM_ID ] ) + { + // TODO DFF_ANIM_ID + } + + if ( pAny[ DFF_ANIM_AFTEREFFECT ] ) + { + sal_Bool bAfterEffect = sal_False; + if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect ) + exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, bAfterEffect, TRANSLATE_NONE ); + } + + if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] ) + { + sal_Int32 nRunTimeContext = 0; + if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext, TRANSLATE_NONE ); + } + if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] ) + { + // TODO DFF_ANIM_ID + } + + if( !xMaster.is() ) + { + Reference< XAnimateColor > xColor( xNode, UNO_QUERY ); + if( xColor.is() ) + { +// sal_uInt32 nColorSpace = xColor->getColorSpace() == AnimationColorSpace::RGB ? 0 : 1; +// exportAnimPropertyuInt32( rStrm, DFF_ANIM_COLORSPACE, nColorSpace, TRANSLATE_NONE ); + + sal_Bool bDirection = !xColor->getDirection(); + exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection, TRANSLATE_NONE ); + } + } + + if ( pAny[ DFF_ANIM_OVERRIDE ] ) + { + sal_Int32 nOverride = 0; + if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride, TRANSLATE_NONE ); + } + + if ( pAny[ DFF_ANIM_MASTERREL ] ) + { + sal_Int32 nMasterRel = 0; + if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel ) + exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel, TRANSLATE_NONE ); + } + +/* todo + Reference< XAudio > xAudio( xNode, UNO_QUERY ); + if( xAudio.is() ) + { + sal_Int16 nEndAfterSlide = 0; + nEndAfterSlide = xAudio->getEndAfterSlide(); + exportAnimPropertyuInt32( rStrm, DFF_ANIM_ENDAFTERSLIDE, nEndAfterSlide, TRANSLATE_NONE ); + } +*/ + Reference< XAnimate > xAnim( xNode, UNO_QUERY ); + if( xAnim.is() ) + { + // TODO: DFF_ANIM_TIMEFILTER + } + if ( pAny[ DFF_ANIM_EVENT_FILTER ] ) + { + // TODO DFF_ANIM_EVENT_FILTER + } + if ( pAny[ DFF_ANIM_VOLUME ] ) + { + // TODO DFF_ANIM_VOLUME + } + return nNodeType; +} + +sal_Bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const ::com::sun::star::uno::Any& rAny, const TranslateMode eTranslateMode ) +{ + sal_Bool bRet = sal_False; + if ( rAny.hasValue() ) + { + switch( rAny.getValueType().getTypeClass() ) + { + case ::com::sun::star::uno::TypeClass_UNSIGNED_SHORT : + case ::com::sun::star::uno::TypeClass_SHORT : + case ::com::sun::star::uno::TypeClass_UNSIGNED_LONG : + case ::com::sun::star::uno::TypeClass_LONG : + { + sal_Int32 nVal = 0; + if ( rAny >>= nVal ) + { + exportAnimPropertyuInt32( rStrm, nPropertyId, nVal, eTranslateMode ); + bRet = sal_True; + } + } + break; + + case ::com::sun::star::uno::TypeClass_DOUBLE : + { + double fVal = 0.0; + if ( rAny >>= fVal ) + { + exportAnimPropertyFloat( rStrm, nPropertyId, fVal, eTranslateMode ); + bRet = sal_True; + } + } + break; + case ::com::sun::star::uno::TypeClass_FLOAT : + { + float fVal = 0.0; + if ( rAny >>= fVal ) + { + if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING ) + { + Any aAny; + rtl::OUString aNumber( rtl::OUString::valueOf( fVal ) ); + aAny <<= aNumber; + exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode ); + } + else + { + exportAnimPropertyFloat( rStrm, nPropertyId, fVal, eTranslateMode ); + bRet = sal_True; + } + } + } + break; + case ::com::sun::star::uno::TypeClass_STRING : + { + rtl::OUString aStr; + if ( rAny >>= aStr ) + { + exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode ); + bRet = sal_True; + } + } + break; + default: + break; + } + } + return bRet; +} +void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const rtl::OUString& rVal, const TranslateMode eTranslateMode ) +{ + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId ); + sal_uInt8 nType = DFF_ANIM_PROP_TYPE_UNISTRING; + rStrm << nType; + rtl::OUString aStr( rVal ); + if ( eTranslateMode != TRANSLATE_NONE ) + ImplTranslateAttribute( aStr, eTranslateMode ); + writeZString( rStrm, aStr ); +} + +void AnimationExporter::exportAnimPropertyFloat( SvStream& rStrm, const sal_uInt16 nPropertyId, const double& rVal, const TranslateMode ) +{ + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId ); + sal_uInt8 nType = DFF_ANIM_PROP_TYPE_FLOAT; + float fFloat = (float)rVal; + rStrm << nType + << fFloat; +} + +void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal, const TranslateMode ) +{ + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId ); + sal_uInt8 nType = DFF_ANIM_PROP_TYPE_INT32 ; + rStrm << nType + << nVal; +} + +void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal, const TranslateMode ) +{ + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId ); + sal_uInt8 nType = DFF_ANIM_PROP_TYPE_BYTE; + rStrm << nType + << nVal; +} + +void AnimationExporter::writeZString( SvStream& rStrm, const rtl::OUString& rVal ) +{ + sal_Int32 i; + for ( i = 0; i < rVal.getLength(); i++ ) + rStrm << rVal[ i ]; + rStrm << (sal_Unicode)0; +} + +void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction ); + + sal_Int32 nConcurrent = 1; + sal_Int32 nNextAction = 1; + sal_Int32 nEndSync = 0; + sal_Int32 nU4 = 0; + sal_Int32 nU5 = 3; + + sal_Int16 nAnimationEndSync = 0; + if ( xNode->getEndSync() >>= nAnimationEndSync ) + { + if ( nAnimationEndSync == AnimationEndSync::ALL ) + nEndSync = 1; + } + rStrm << nConcurrent + << nNextAction + << nEndSync + << nU4 + << nU5; + +} + +// nFlags Bit 6 = fixInteractiveSequenceTiming (for child) +// nFlags Bit 5 = fixInteractiveSequenceTiming (for root) +// nFlags Bit 4 = first node of main sequence -> begin event next has to be replaced to indefinite +void AnimationExporter::exportAnimEvent( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Int32 nFlags ) +{ + sal_uInt16 i; + for ( i = 0; i < 4; i++ ) + { + sal_Int32 nU1 = 0; + sal_Int32 nTrigger = 0; + sal_Int32 nU3 = 0; + sal_Int32 nBegin = 0; + + sal_Bool bCreateEvent = sal_False; + Any aSource; + + switch( i ) + { + case 0 : + case 1 : + { + Any aAny; + Event aEvent; + com::sun::star::animations::Timing eTiming; + if ( i == 0 ) + { + if ( nFlags & 0x20 ) + { + // taking the first child + Reference< XEnumerationAccess > xEA( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xE( xEA->createEnumeration(), UNO_QUERY_THROW ); + if ( xE.is() && xE->hasMoreElements() ) + { +// while( xE->hasMoreElements() ) + { + Reference< XAnimationNode > xClickNode( xE->nextElement(), UNO_QUERY ); + aAny = xClickNode->getBegin(); + } + } + } + else if ( nFlags & 0x40 ) + { + // begin has to be replaced with void, so don't do anything + } + else + { + aAny = xNode->getBegin(); + if ( nFlags & 0x10 ) // replace ON_NEXT with IDEFINITE + { + if ( ( aAny >>= aEvent ) && ( aEvent.Trigger == EventTrigger::ON_NEXT ) ) + { + eTiming = Timing_INDEFINITE; + aAny <<= eTiming; + } + } + } + } + else + aAny = xNode->getEnd(); + + double fTiming = 0.0; + if ( aAny >>= aEvent ) + { + bCreateEvent = sal_True; + switch( aEvent.Trigger ) + { + case EventTrigger::NONE : nTrigger = 0; break; + case EventTrigger::ON_BEGIN : nTrigger = 1; break; + case EventTrigger::ON_END : nTrigger = 2; break; + case EventTrigger::BEGIN_EVENT : nTrigger = 3; break; + case EventTrigger::END_EVENT : nTrigger = 4; nU1 = 2; nU3 = mnCurrentGroup; break; + case EventTrigger::ON_CLICK : nTrigger = 5; break; + case EventTrigger::ON_DBL_CLICK : nTrigger = 6; break; + case EventTrigger::ON_MOUSE_ENTER : nTrigger = 7; break; + case EventTrigger::ON_MOUSE_LEAVE : nTrigger = 8; break; + case EventTrigger::ON_NEXT : nTrigger = 9; break; + case EventTrigger::ON_PREV : nTrigger = 10; break; + case EventTrigger::ON_STOP_AUDIO : nTrigger = 11; break; + } + if ( aEvent.Offset.hasValue() ) + { + if ( aEvent.Offset >>= eTiming ) + { + if ( eTiming == Timing_INDEFINITE ) + nBegin = -1; + } + else if ( aEvent.Offset >>= fTiming ) + nBegin = (sal_Int32)( fTiming * 1000.0 ); + } + aSource = aEvent.Source; + } + else if ( aAny >>= eTiming ) + { + bCreateEvent = sal_True; + if ( eTiming == Timing_INDEFINITE ) + nBegin = -1; + } + else if ( aAny >>= fTiming ) + { + bCreateEvent = sal_True; + if ( eTiming == Timing_INDEFINITE ) + nBegin = (sal_Int32)( fTiming * 1000.0 ); + } + } + break; + + case 2 : + { + if ( nFlags & ( 1 << i ) ) + { + bCreateEvent = sal_True; + nU1 = 1; + nTrigger = 9; + } + } + break; + case 3 : + { + if ( nFlags & ( 1 << i ) ) + { + bCreateEvent = sal_True; + nU1 = 1; + nTrigger = 10; + } + } + break; + }; + if ( bCreateEvent ) + { + EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 ); + { + EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger ); + rStrm << nU1 + << nTrigger + << nU3 + << nBegin; + } + exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 ); + } + } +} + +Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, const rtl::OUString& rAttributeName ) const +{ + rtl::OUString aDest; + if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "X" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Y" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Width" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Height" ) ) + ) + { + rtl::OUString aStr; + if ( rSourceValue >>= aStr ) + { + ImplTranslateAttribute( aStr, TRANSLATE_MEASURE ); + aDest += aStr; + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Rotate" ) ) // "r" or "style.rotation" ? + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "SkewX" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Opacity" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharHeight" ) ) + ) + { + double fNumber = 0.0; + if ( rSourceValue >>= fNumber ) + aDest += rtl::OUString::valueOf( fNumber ); + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Color" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FillColor" ) ) // "Fillcolor" or "FillColor" ? + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "LineColor" ) ) + || rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharColor" ) ) + ) + { + sal_Int32 nColor = 0; + Sequence< double > aHSL( 3 ); + rtl::OUString aP( RTL_CONSTASCII_USTRINGPARAM( "," ) ); + if ( rSourceValue >>= aHSL ) + { + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hsl(" ) ); + aDest += rtl::OUString::valueOf( (sal_Int32)( aHSL[ 0 ] / ( 360.0 / 255 ) ) ); + aDest += aP; + aDest += rtl::OUString::valueOf( (sal_Int32)( aHSL[ 1 ] * 255.0 ) ); + aDest += aP; + aDest += rtl::OUString::valueOf( (sal_Int32)( aHSL[ 2 ] * 255.0 ) ); + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ")" ) ); + } + else if ( rSourceValue >>= nColor ) + { + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "rgb(" ) ); + aDest += rtl::OUString::valueOf( (sal_Int32)( (sal_Int8)nColor ) ); + aDest += aP; + aDest += rtl::OUString::valueOf( (sal_Int32)( (sal_Int8)( nColor >> 8 ) ) ); + aDest += aP; + aDest += rtl::OUString::valueOf( (sal_Int32)( (sal_Int8)( nColor >> 16 ) ) ); + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ")" ) ); + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "FillStyle" ) ) ) + { + ::com::sun::star::drawing::FillStyle eFillStyle; + if ( rSourceValue >>= eFillStyle ) + { + if ( eFillStyle == ::com::sun::star::drawing::FillStyle_NONE ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "none" ) ); // ? + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "solid" ) ); + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "LineStyle" ) ) ) + { + ::com::sun::star::drawing::LineStyle eLineStyle; + if ( rSourceValue >>= eLineStyle ) + { + if ( eLineStyle == ::com::sun::star::drawing::LineStyle_NONE ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) ); + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) ); + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharWeight" ) ) ) + { + float fFontWeight = 0.0; + if ( rSourceValue >>= fFontWeight ) + { + if ( fFontWeight == com::sun::star::awt::FontWeight::BOLD ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "bold" ) ); + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "normal" ) ); + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharUnderline" ) ) ) + { + sal_Int16 nFontUnderline = 0; + if ( rSourceValue >>= nFontUnderline ) + { + if ( nFontUnderline == com::sun::star::awt::FontUnderline::NONE ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "false" ) ); + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "true" ) ); + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "CharPosture" ) ) ) + { + ::com::sun::star::awt::FontSlant eFontSlant; + if ( rSourceValue >>= eFontSlant ) + { + if ( eFontSlant == com::sun::star::awt::FontSlant_ITALIC ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "italic" ) ); + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "normal" ) ); // ? + } + } + else if ( rAttributeName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Visibility" ) ) ) + { + sal_Bool bVisible = sal_True; + if ( rSourceValue >>= bVisible ) + { + if ( bVisible ) + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "visible" ) ); + else + aDest += rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "hidden" ) ); + } + } + Any aRet; + if ( aDest.getLength() ) + aRet <<= aDest; + else + aRet = rSourceValue; + return aRet; +} + +void AnimationExporter::exportAnimateSet( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType ) +{ + Reference< XAnimateSet > xSet( xNode, UNO_QUERY ); + if( xSet.is() ) + { + EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 ); + { + EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData ); + sal_uInt32 nId1 = 1; // ?? + sal_uInt32 nId2 = 1; // ?? + rStrm << nId1 << nId2; + } + Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) ); + if ( aConvertedValue.hasValue() ) + exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE ); + exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType ); + } +} + +sal_uInt32 GetValueTypeForAttributeName( const rtl::OUString& rAttributeName ) +{ + sal_uInt32 nValueType = 0; + +/* + AnimationValueType::STRING == 0; + AnimationValueType::NUMBER == 1; + AnimationValueType::COLOR == 2; +*/ + + struct Entry + { + const sal_Char* pName; + sal_uInt8 nType; + }; + static const Entry lcl_attributeMap[] = + { + { "charcolor", 2 }, + { "charfontname", 0 }, + { "charheight", 1 }, + { "charposture", 0 }, + // TODO(Q1): This should prolly be changed in PPT import + // { "charrotation", ATTRIBUTE_CHAR_ROTATION }, + { "charrotation", 1 }, + { "charunderline", 0 }, + { "charweight", 0 }, + { "color", 2 }, + { "dimcolor", 2 }, + { "fillcolor", 2 }, + { "fillstyle", 0 }, + { "height", 1 }, + { "linecolor", 2 }, + { "linestyle", 0 }, + { "opacity", 0 }, + { "rotate", 1 }, + { "skewx", 1 }, + { "skewy", 1 }, + { "visibility", 1 }, + { "width", 1 }, + { "x", 1 }, + { "y", 1 }, + { NULL, 0 } + }; + const Entry* pPtr = &lcl_attributeMap[ 0 ]; + while( pPtr->pName ) + { + if ( rAttributeName.equalsIgnoreAsciiCaseAscii( pPtr->pName ) ) + { + nValueType = pPtr->nType; + break; + } + pPtr++; + } + DBG_ASSERT( pPtr->pName, "GetValueTypeForAttributeName, unknown property value!" ); + return nValueType; +} + +void AnimationExporter::exportAnimate( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + Reference< XAnimate > xAnimate( xNode, UNO_QUERY ); + if ( xAnimate.is() ) + { + Any aBy ( xAnimate->getBy() ); + Any aFrom( xAnimate->getFrom() ); + Any aTo ( xAnimate->getTo() ); + + EscherExContainer aContainer( rStrm, DFF_msofbtAnimate, 0 ); + { + EscherExAtom aAnimateData( rStrm, DFF_msofbtAnimateData ); + sal_uInt32 nBits = 0x38; + sal_Int16 nTmp = xAnimate->getCalcMode(); + sal_uInt32 nCalcMode = /* (nTmp == AnimationCalcMode::FORMULA) ? 2 : */ (nTmp == AnimationCalcMode::LINEAR) ? 1 : 0; + nTmp = xAnimate->getValueType(); + sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() ); + + if ( aBy.hasValue() ) + nBits |= 1; + if ( aFrom.hasValue() ) + nBits |= 2; + if ( aTo.hasValue() ) + nBits |= 4; + + rStrm << nCalcMode + << nBits + << nValueType; + } + if ( aBy.hasValue() ) + exportAnimProperty( rStrm, 1, aBy, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE ); + if ( aFrom.hasValue() ) + exportAnimProperty( rStrm, 2, aFrom, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE ); + if ( aTo.hasValue() ) + exportAnimProperty( rStrm, 3, aTo, TRANSLATE_NUMBER_TO_STRING | TRANSLATE_MEASURE ); + + exportAnimateKeyPoints( rStrm, xAnimate ); + exportAnimateTarget( rStrm, xNode ); + } +} + +void AnimationExporter::exportAnimateTarget( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_uInt32 nForceAttributeNames, int nAfterEffectType ) +{ + EscherExContainer aAnimateTarget( rStrm, DFF_msofbtAnimateTarget, 0 ); + Reference< XAnimate > xAnimate( xNode, UNO_QUERY ); + if ( xAnimate.is() ) + { + { + EscherExAtom aAnimateTargetSettings( rStrm, DFF_msofbtAnimateTargetSettings, 0 ); + // 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" + sal_uInt32 nBits = 0; + sal_uInt32 nAdditive = 0; + sal_uInt32 nAccumulate = 0; + sal_uInt32 nTransformType = 0; + if ( xAnimate.is() ) + { + if ( xAnimate->getAttributeName().getLength() ) + nBits |= 4; // what is attributeName ?, maybe this is set if a DFF_msofbtAnimateAttributeNames is written + sal_Int16 nAdditiveMode = xAnimate->getAdditive(); + if ( nAdditiveMode != AnimationAdditiveMode::BASE ) + { + nBits |= 1; + switch( nAdditiveMode ) + { + case AnimationAdditiveMode::SUM : nAdditive = 1; break; + case AnimationAdditiveMode::REPLACE : nAdditive = 2; break; + case AnimationAdditiveMode::MULTIPLY : nAdditive = 3; break; + case AnimationAdditiveMode::NONE : nAdditive = 4; break; + } + } + if ( xAnimate->getAccumulate() ) + { + nBits |= 2; + nAccumulate = 1; + } + } + rStrm << nBits + << nAdditive + << nAccumulate + << nTransformType; + } + if ( xAnimate->getAttributeName().getLength() || nForceAttributeNames ) + { + EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 ); + rtl::OUString aAttributeName( xAnimate->getAttributeName() ); + if ( nForceAttributeNames ) + { + switch( nForceAttributeNames ) + { + case 1 : aAttributeName = rtl::OUString::createFromAscii( "r" ); break; + } + } + sal_Int32 nIndex = 0; + do + { + OUString aToken( aAttributeName.getToken( 0, ';', nIndex ) ); + exportAnimPropertyString( rStrm, 0, aToken, TRANSLATE_ATTRIBUTE ); + } + while ( nIndex >= 0 ); + } + + if( nAfterEffectType != AFTEREFFECT_NONE ) + { + EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet ); + exportAnimPropertyuInt32( rStrm, 6, 1, TRANSLATE_NONE ); + if( nAfterEffectType == AFTEREFFECT_COLOR ) + { + exportAnimPropertyuInt32( rStrm, 4, 0, TRANSLATE_NONE ); + exportAnimPropertyuInt32( rStrm, 5, 0, TRANSLATE_NONE ); + } + } + exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), sal_False ); + } +} + +void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any aAny, const sal_Bool bCreate2b01Atom ) +{ + Reference< XShape > xShape; + aAny >>= xShape; + sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph + sal_Int32 begin = -1; + sal_Int32 end = -1; + + if( !xShape.is() ) + { + ParagraphTarget aParaTarget; + if( aAny >>= aParaTarget ) + xShape = aParaTarget.Shape; + if ( xShape.is() ) + { + // now calculating the character range for the paragraph + sal_Int16 nParagraph = aParaTarget.Paragraph; + Reference< XSimpleText > xText( xShape, UNO_QUERY ); + if ( xText.is() ) + { + nRefMode = 2; + Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY ); + if ( xTextParagraphEnumerationAccess.is() ) + { + Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() ); + if ( xTextParagraphEnumeration.is() ) + { + sal_Int16 nCurrentParagraph; + begin = end = nCurrentParagraph = 0; + while ( xTextParagraphEnumeration->hasMoreElements() ) + { + Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY ); + if ( xTextRange.is() ) + { + rtl::OUString aParaText( xTextRange->getString() ); + sal_Int32 nLength = aParaText.getLength() + 1; + end += nLength; + if ( nCurrentParagraph == nParagraph ) + break; + nCurrentParagraph++; + begin += nLength; + } + } + } + } + } + } + } + if ( xShape.is() || bCreate2b01Atom ) + { + EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement ); + if ( xShape.is() ) + { + EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference ); + + sal_uInt32 nRefType = 1; // TODO: nRefType == 2 -> Sound; + sal_uInt32 nRefId = ((EscherSolverContainer&)mrSolverContainer).GetShapeId( xShape ); + + rStrm << nRefMode + << nRefType + << nRefId + << begin + << end; + } + if ( bCreate2b01Atom ) + { + EscherExAtom a2b01Atom( rStrm, 0x2b01 ); + rStrm << (sal_uInt32)1; // ? + } + } +} + +void AnimationExporter::exportAnimateKeyPoints( SvStream& rStrm, const Reference< XAnimate >& xAnimate ) +{ + Sequence< double > aKeyTimes( xAnimate->getKeyTimes() ); + Sequence< Any > aValues( xAnimate->getValues() ); + OUString aFormula( xAnimate->getFormula() ); + if ( aKeyTimes.getLength() ) + { + EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints ); + sal_Int32 i; + for ( i = 0; i < aKeyTimes.getLength(); i++ ) + { + { + EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime ); + sal_Int32 nKeyTime = (sal_Int32)( aKeyTimes[ i ] * 1000.0 ); + rStrm << nKeyTime; + } + Any aAny[ 2 ]; + if ( aValues[ i ].hasValue() ) + { + ValuePair aPair; + if ( aValues[ i ] >>= aPair ) + { + aAny[ 0 ] = convertAnimateValue( aPair.First, xAnimate->getAttributeName() ); + aAny[ 1 ] = convertAnimateValue( aPair.Second, xAnimate->getAttributeName() ); + } + else + { + aAny[ 0 ] = convertAnimateValue( aValues[ i ], xAnimate->getAttributeName() ); + } + if ( !i && aFormula.getLength() ) + { + ImplTranslateAttribute( aFormula, TRANSLATE_MEASURE ); + aAny[ 1 ] <<= aFormula; + } + exportAnimProperty( rStrm, 0, aAny[ 0 ], TRANSLATE_NONE ); + exportAnimProperty( rStrm, 1, aAny[ 1 ], TRANSLATE_NONE ); + } + } + } +} + +void AnimationExporter::exportAnimValue( SvStream& rStrm, const Reference< XAnimationNode >& xNode, const sal_Bool bExportAlways ) +{ + Any aAny; + // repeat count (0) + double fRepeat = 0.0; + float fRepeatCount = 0.0; + com::sun::star::animations::Timing eTiming; + aAny = xNode->getRepeatCount(); + if ( aAny >>= eTiming ) + { + if ( eTiming == Timing_INDEFINITE ) + fRepeatCount = ((float)3.40282346638528860e+38); + } + else if ( aAny >>= fRepeat ) + fRepeatCount = (float)fRepeat; + if ( fRepeatCount != 0.0 ) + { + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue ); + sal_uInt32 nType = 0; + rStrm << nType + << fRepeatCount; + } + // accelerate (3) + float fAccelerate = (float)xNode->getAcceleration(); + if ( bExportAlways || ( fAccelerate != 0.0 ) ) + { + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue ); + sal_uInt32 nType = 3; + rStrm << nType + << fAccelerate; + } + + // decelerate (4) + float fDecelerate = (float)xNode->getDecelerate(); + if ( bExportAlways || ( fDecelerate != 0.0 ) ) + { + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue ); + sal_uInt32 nType = 4; + rStrm << nType + << fDecelerate; + } + + // autoreverse (5) + sal_Bool bAutoReverse = xNode->getAutoReverse(); + if ( bExportAlways || bAutoReverse ) + { + EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue ); + sal_uInt32 nType = 5; + sal_uInt32 nVal = bAutoReverse ? 1 : 0; + rStrm << nType + << nVal; + } +} + +void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY ); + if ( xFilter.is() ) + { + EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter ); + { + EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData ); + sal_uInt32 nBits = 3; // bit 0 -> use AnimAttributeValue + // bit 1 -> use nTransition + + sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1; + rStrm << nBits + << nTransition; + } + const sal_Char* pFilter = transition::find( xFilter->getTransition(), xFilter->getSubtype(), xFilter->getDirection() ); + if ( pFilter ) + { + const OUString aStr( OUString::createFromAscii( pFilter ) ); + exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE ); + } + exportAnimateTarget( rStrm, xNode ); + } +} + +void AnimationExporter::exportAnimateMotion( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + Reference< XAnimateMotion > xMotion( xNode, UNO_QUERY ); + if ( xMotion.is() ) + { + EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion ); + { + { //SJ: Ignored from import filter + EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData ); + sal_uInt32 nBits = 0x98; + sal_uInt32 nOrigin = 0x2; + float fByX = 100.0; // nBits&1 + float fByY = 100.0; // nBits&1 + float fFromX = 0.0; // nBits&2 + float fFromY = 0.0; // nBits&2 + float fToX = 100.0; // nBits&4 + float fToY = 100.0; // nBits&4 + rStrm << nBits << fByX << fByY << fFromX << fFromY << fToX << fToY << nOrigin; + } +/* ? + { + EscherExAtom aF137( rStrm, 0xf137 ); + } +*/ + OUString aStr; + if ( xMotion->getPath() >>= aStr ) + { + if ( aStr.getLength() ) + exportAnimPropertyString( rStrm, 1, aStr, TRANSLATE_NONE ); + } + exportAnimateTarget( rStrm, xNode ); + } + } +} + +void AnimationExporter::exportAnimateTransform( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + Reference< XAnimateTransform > xTransform( xNode, UNO_QUERY ); + if ( xTransform.is() ) + { + if ( xTransform->getTransformType() == AnimationTransformType::SCALE ) + { + EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale ); + { + EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData ); + sal_uInt32 nBits = 0; + sal_uInt32 nZoomContents = 1; + float fByX = 100.0; + float fByY = 100.0; + float fFromX = 0.0; + float fFromY = 0.0; + float fToX = 100.0; + float fToY = 100.0; + + double fX = 0.0, fY = 0.0; + ValuePair aPair; + if ( xTransform->getBy() >>= aPair ) + { + if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) ) + { + nBits |= 1; + fByX = (float)( fX * 100 ); + fByY = (float)( fY * 100 ); + } + } + if ( xTransform->getFrom() >>= aPair ) + { + if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) ) + { + nBits |= 2; + fFromX = (float)( fX * 100 ); + fFromY = (float)( fY * 100 ); + } + } + if( xTransform->getTo() >>= aPair ) + { + if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) ) + { + nBits |= 4; + fToX = (float)( fX * 100 ); + fToY = (float)( fY * 100 ); + } + } + + // TODO: ZoomContents: + //if( nBits & 8 ) + //( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" ); + + rStrm << nBits << fByX << fByY << fFromX << fFromY << fToX << fToY << nZoomContents; + } + exportAnimateTarget( rStrm, xNode ); + } + else if ( xTransform->getTransformType() == AnimationTransformType::ROTATE ) + { + EscherExContainer aAnimateRotation( rStrm, DFF_msofbtAnimateRotation ); + { + EscherExAtom aAnimateRotationData( rStrm, DFF_msofbtAnimateRotationData ); + sal_uInt32 nBits = 0; + sal_uInt32 nU1 = 0; + float fBy = 360.0; + float fFrom = 0.0; + float fTo = 360.0; + + double fVal = 0.0; + if ( xTransform->getBy() >>= fVal ) + { + nBits |= 1; + fBy = (float)fVal; + } + if ( xTransform->getFrom() >>= fVal ) + { + nBits |= 2; + fFrom = (float)fVal; + } + if ( xTransform->getTo() >>= fVal ) + { + nBits |= 4; + fTo = (float)fVal; + } + rStrm << nBits << fBy << fFrom << fTo << nU1; + } + exportAnimateTarget( rStrm, xNode, 1 ); + } + } +} + +sal_Bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC ) const +{ + sal_Bool bIsColor = sal_True; + + rMode = 0; + if ( nColorSpace == AnimationColorSpace::HSL ) + rMode = 1; + + sal_Int32 nColor = 0; + Sequence< double > aHSL( 3 ); + if ( rAny >>= nColor ) // RGB color + { + rA = (sal_uInt8)( nColor >> 24 ); + rB = (sal_uInt8)( nColor >> 8 ); + rC = (sal_uInt8)( nColor ); + } + else if ( rAny >>= aHSL ) // HSL + { + rA = (sal_Int32) ( aHSL[ 0 ] * 255.0 / 360.0 ); + rB = (sal_Int32) ( aHSL[ 1 ] * 255.0 ); + rC = (sal_Int32) ( aHSL[ 2 ] * 255.0 ); + } + else + bIsColor = sal_False; + return bIsColor; +} + +void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType ) +{ + Reference< XAnimateColor > xColor( xNode, UNO_QUERY ); + if ( xColor.is() ) + { + EscherExContainer aAnimateColor( rStrm, DFF_msofbtAnimateColor ); + { + EscherExAtom aAnimateColorData( rStrm, DFF_msofbtAnimateColorData ); + sal_uInt32 nBits = 8; + + sal_Int32 nByMode, nByA, nByB, nByC; + nByMode = nByA = nByB = nByC = 0; + + sal_Int32 nFromMode, nFromA, nFromB, nFromC; + nFromMode = nFromA = nFromB = nFromC = 0; + + sal_Int32 nToMode, nToA, nToB, nToC; + nToMode = nToA = nToB = nToC = 0; + + sal_Int16 nColorSpace = xColor->getColorInterpolation(); + + Any aAny( xColor->getBy() ); + if ( aAny.hasValue() ) + { + if ( getColorAny( aAny, nColorSpace, nByMode, nByA, nByB, nByC ) ) + nBits |= 0x11; + } + aAny = xColor->getFrom(); + if ( aAny.hasValue() ) + { + if ( getColorAny( aAny, nColorSpace, nFromMode, nFromA, nFromB, nFromC ) ) + nBits |= 0x12; + } + aAny = xColor->getTo(); + if ( aAny.hasValue() ) + { + if ( getColorAny( aAny, nColorSpace, nToMode, nToA, nToB, nToC ) ) + nBits |= 0x14; + } + rStrm << nBits + << nByMode << nByA << nByB << nByC + << nFromMode << nFromA << nFromB << nFromC + << nToMode << nToA << nToB << nToC; + } + exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType ); + } +} + +void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode ) +{ + Reference< XIterateContainer > xIterate( xNode, UNO_QUERY ); + if ( xIterate.is() ) + { + EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration ); + + float fInterval = 10.0; + sal_Int32 nTextUnitEffect = 0; + sal_Int32 nU1 = 1; + sal_Int32 nU2 = 1; + sal_Int32 nU3 = 0xe; + + sal_Int16 nIterateType = xIterate->getIterateType(); + switch( nIterateType ) + { + case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break; + case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break; + } + + fInterval = (float)xIterate->getIterateInterval(); + + // convert interval from absolute to percentage + double fDuration = 0.0; + + Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY ); + if( xEnumerationAccess.is() ) + { + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_QUERY ); + 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( fDuration ) + fInterval = (float)(100.0 * fInterval / fDuration); + + rStrm << fInterval << nTextUnitEffect << nU1 << nU2 << nU3; + aTarget = xIterate->getTarget(); + } +} + +} // namespace ppt; + |