/* -*- 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/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/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/ValuePair.hpp>
#include <com/sun/star/animations/AnimationColorSpace.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/drawing/XDrawPage.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 <oox/ppt/pptfilterhelpers.hxx>
#include "pptexanimations.hxx"
#include "pptexsoundcollection.hxx"
#include "../ppt/pptanimations.hxx"
#include <filter/msfilter/escherex.hxx>
#include <osl/diagnose.h>
#include <tools/debug.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <o3tl/string_view.hxx>
#include <algorithm>
using ::com::sun::star::uno::Any;
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::Exception;
using ::com::sun::star::beans::NamedValue;
using ::com::sun::star::container::XEnumerationAccess;
using ::com::sun::star::container::XEnumeration;
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
{
static void ImplTranslateAttribute( OUString& rString, const TranslateMode eTranslateMode )
{
if ( eTranslateMode == TRANSLATE_NONE )
return;
if ( ( eTranslateMode & TRANSLATE_VALUE ) || ( eTranslateMode & TRANSLATE_ATTRIBUTE ) )
{
const oox::ppt::ImplAttributeNameConversion* p = oox::ppt::getAttributeConversionList();
while( p->mpAPIName )
{
if( rString.equalsAscii( p->mpAPIName ) )
break;
p++;
}
if( p->mpMSName )
{
if ( eTranslateMode & TRANSLATE_VALUE )
{
rString = "#";
rString += OUString::createFromAscii( p->mpMSName );
}
else
rString = OUString::createFromAscii( p->mpMSName );
}
}
else if ( eTranslateMode & TRANSLATE_MEASURE )
{
const char* pDest[] = { "#ppt_x", "#ppt_y", "#ppt_w", "#ppt_h", nullptr };
const char* pSource[] = { "x", "y", "width", "height", nullptr };
sal_Int32 nIndex = 0;
const char** ps = pSource;
const char** pd = pDest;
while( *ps )
{
if (nIndex == -1)
nIndex = 0;
const OUString aSearch( OUString::createFromAscii( *ps ) );
while( (nIndex = rString.indexOf( aSearch, nIndex )) != -1 )
{
sal_Int32 nLength = aSearch.getLength();
if( nIndex && ( rString[nIndex-1] == '#' ) )
{
nIndex--;
nLength++;
}
const OUString aNew( OUString::createFromAscii( *pd ) );
rString = rString.replaceAt( nIndex, nLength, aNew );
nIndex += aNew.getLength();
}
ps++;
pd++;
}
}
}
sal_uInt32 AnimationExporter::TranslatePresetSubType( const sal_uInt32 nPresetClass, const sal_uInt32 nPresetId, std::u16string_view rPresetSubType )
{
sal_uInt32 nPresetSubType = 0;
bool bTranslated = false;
if ( ( nPresetClass == sal_uInt32(EffectPresetClass::ENTRANCE) ) || ( nPresetClass == sal_uInt32(EffectPresetClass::EXIT) ) )
{
if ( nPresetId != 21 )
{
switch( nPresetId )
{
case 5 :
{
if ( rPresetSubType == u"downward" )
{
nPresetSubType = 5;
bTranslated = true;
}
else if ( rPresetSubType == u"across" )
{
nPresetSubType = 10;
bTranslated = true;
}
}
break;
case 17 :
{
if ( rPresetSubType == u"across" )
{
nPresetSubType = 10;
bTranslated = true;
}
}
break;
case 18 :
{
if ( rPresetSubType == u"right-to-top" )
{
nPresetSubType = 3;
bTranslated = true;
}
else if ( rPresetSubType == u"right-to-bottom" )
{
nPresetSubType = 6;
bTranslated = true;
}
else if ( rPresetSubType == u"left-to-top" )
{
nPresetSubType = 9;
bTranslated = true;
}
else if ( rPresetSubType == u"left-to-bottom" )
{
nPresetSubType = 12;
bTranslated = true;
}
}
break;
}
}
if ( !bTranslated )
{
const oox::ppt::convert_subtype* p = oox::ppt::convert_subtype::getList();
while( p->mpStrSubType )
{
if ( o3tl::equalsAscii( rPresetSubType, p->mpStrSubType ) )
{
nPresetSubType = p->mnID;
bTranslated = true;
break;
}
p++;
}
}
}
if ( !bTranslated )
nPresetSubType = o3tl::toUInt32(rPresetSubType);
return nPresetSubType;
}
const char* AnimationExporter::FindTransitionName( const sal_Int16 nType, const sal_Int16 nSubType, const bool bDirection )
{
const char* pRet = nullptr;
int nFit = 0;
const oox::ppt::transition* p = oox::ppt::transition::getList();
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& WriteAnimationNode(SvStream& rOut, AnimationNode const & rNode )
{
rOut.WriteInt32( rNode.mnU1 );
rOut.WriteInt32( rNode.mnRestart );
rOut.WriteInt32( rNode.mnGroupType );
rOut.WriteInt32( rNode.mnFill );
rOut.WriteInt32( rNode.mnU3 );
rOut.WriteInt32( rNode.mnU4 );
rOut.WriteInt32( rNode.mnDuration );
rOut.WriteInt32( rNode.mnNodeType );
return rOut;
}
AnimationExporter::AnimationExporter( const EscherSolverContainer& rSolverContainer, ppt::ExSoundCollection& rExSoundCollection ) :
mrSolverContainer ( rSolverContainer ),
mrExSoundCollection ( rExSoundCollection ),
mnCurrentGroup(0)
{
}
sal_Int16 AnimationExporter::GetFillMode( const Reference< XAnimationNode >& xNode, const sal_Int16 nFillDefault )
{
sal_Int16 nFill = xNode->getFill();
//#i119699 <Animation> The animation effect "Emphasis->FlashBulb" play incorrectly in Aoo saves a .ppt to another .ppt and plays the saved one.
//#i119740 <Animation> The animation effect "Entrance->Flash Once" fails to play in Aoo while Aoo saves a .ppt to another .ppt and plays the saved one.
if ((xNode->getType() == AnimationNodeType::ANIMATE)
||(xNode->getType() == AnimationNodeType::SET)
||(xNode->getType() == AnimationNodeType::TRANSITIONFILTER))
{
if ( nFill == AnimationFill::DEFAULT )
return nFill;
}
if ( nFill == AnimationFill::DEFAULT )
{
nFill = nFillDefault;
}
if( nFill == AnimationFill::AUTO )
{
nFill = AnimationFill::REMOVE;
bool bIsIndefiniteTiming = 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, DFF_msofbtAnimGroup, 1, 0, false, AnimationFill::AUTO );
}
}
}
void AnimationExporter::processAfterEffectNodes( const Reference< XAnimationNode >& xRootNode )
{
try
{
Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW );
Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), css::uno::UNO_SET_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(), css::uno::UNO_SET_THROW );
while( xEnumeration2->hasMoreElements() )
{
Reference< XAnimationNode > xChildNode( xEnumeration2->nextElement(), UNO_QUERY_THROW );
Reference< XEnumerationAccess > xEnumerationAccess3( xChildNode, UNO_QUERY_THROW );
Reference< XEnumeration > xEnumeration3( xEnumerationAccess3->createEnumeration(), css::uno::UNO_SET_THROW );
while( xEnumeration3->hasMoreElements() )
{
Reference< XAnimationNode > xChildNode2( xEnumeration3->nextElement(), UNO_QUERY_THROW );
Reference< XEnumerationAccess > xEnumerationAccess4( xChildNode2, UNO_QUERY_THROW );
Reference< XEnumeration > xEnumeration4( xEnumerationAccess4->createEnumeration(), css::uno::UNO_SET_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;
const Sequence< NamedValue > aUserData( xChildNode3->getUserData() );
const NamedValue* p = std::find_if(aUserData.begin(), aUserData.end(),
[](const NamedValue& rProp) { return rProp.Name == "master-element"; });
if (p != aUserData.end())
p->Value >>= xMaster;
AfterEffectNodePtr pAfterEffectNode = std::make_shared<AfterEffectNode>( xChildNode3, xMaster );
maAfterEffectNodes.push_back( pAfterEffectNode );
}
break;
}
}
}
}
}
}
}
catch( Exception& )
{
TOOLS_WARN_EXCEPTION( "sd", "(@CL)AnimationExporter::processAfterEffectNodes()" );
}
}
bool AnimationExporter::isAfterEffectNode( const Reference< XAnimationNode >& xNode ) const
{
return std::any_of(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
[&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxNode == xNode; });
}
bool AnimationExporter::hasAfterEffectNode( const Reference< XAnimationNode >& xNode, Reference< XAnimationNode >& xAfterEffectNode ) const
{
auto aIter = std::find_if(maAfterEffectNodes.begin(), maAfterEffectNodes.end(),
[&xNode](const AfterEffectNodePtr& rxNode) { return rxNode->mxMaster == xNode; });
if (aIter != maAfterEffectNodes.end())
{
xAfterEffectNode = (*aIter)->mxNode;
return true;
}
return false;
}
// check if this group only contain empty groups. this may happen when
// after effect nodes are not exported at their 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();
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 > const & xNode_in, const sal_uInt16 nContainerRecType,
const sal_uInt16 nInstance, const sal_Int32 nGroupLevel, const bool bTakeBackInteractiveSequenceTiming, const sal_Int16 nFDef )
{
auto xNode = xNode_in;
if( (nGroupLevel == 4) && isEmptyNode( xNode ) )
return;
if ( ( nContainerRecType == DFF_msofbtAnimGroup ) && ( nGroupLevel == 2 ) && isEmptyNode( xNode ) )
return;
if( nContainerRecType == DFF_msofbtAnimGroup )
mnCurrentGroup++;
bool bTakeBackInteractiveSequenceTimingForChild = false;
sal_Int16 nFillDefault = GetFillMode( xNode, nFDef );
Reference< XAnimationNode > xAudioNode;
static sal_uInt32 nAudioGroup;
{
bool bSkipChildren = false;
EscherExContainer aContainer( rStrm, nContainerRecType, nInstance );
switch( xNode->getType() )
{
case AnimationNodeType::CUSTOM :
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
break;
case AnimationNodeType::PAR :
{
exportAnimNode( rStrm, xNode, 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, nFillDefault );
sal_Int16 nNodeType = exportAnimPropertySet( rStrm, xNode );
sal_Int32 nFlags = 12;
if ( ( nGroupLevel == 1 ) && ( nNodeType == css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE ) )
{
nFlags |= 0x20;
bTakeBackInteractiveSequenceTimingForChild = true;
}
exportAnimAction( rStrm, xNode );
exportAnimEvent( rStrm, xNode, nFlags );
exportAnimValue( rStrm, xNode, false );
}
break;
case AnimationNodeType::ITERATE :
{
{
EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
AnimationNode 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;
}
WriteAnimationNode( rStrm, aAnim );
}
exportIterate( rStrm, xNode );
exportAnimPropertySet( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
break;
case AnimationNodeType::ANIMATE :
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
exportAnimate( rStrm, xNode );
}
break;
case AnimationNodeType::SET :
{
bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
if( (nGroupLevel != 4) || !bIsAfterEffectNode )
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimateSet( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_SET : AFTEREFFECT_NONE );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
else
{
bSkipChildren = true;
}
}
break;
case AnimationNodeType::ANIMATEMOTION :
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimateMotion( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
break;
case AnimationNodeType::ANIMATECOLOR :
{
bool bIsAfterEffectNode( isAfterEffectNode( xNode ) );
if( (nGroupLevel != 4) || !bIsAfterEffectNode )
{
if( bIsAfterEffectNode )
xNode = createAfterEffectNodeClone( xNode );
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimateColor( rStrm, xNode, bIsAfterEffectNode ? AFTEREFFECT_COLOR : AFTEREFFECT_NONE );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
else
{
bSkipChildren = true;
}
}
break;
case AnimationNodeType::ANIMATETRANSFORM :
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimateTransform( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
}
break;
case AnimationNodeType::TRANSITIONFILTER :
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
exportAnimEvent( rStrm, xNode );
exportAnimValue( rStrm, xNode, false );
exportTransitionFilter( rStrm, xNode );
}
break;
case AnimationNodeType::AUDIO : // #i58428#
{
exportAnimNode( rStrm, xNode, nFillDefault );
exportAnimPropertySet( rStrm, xNode );
Reference< XAudio > xAudio( xNode, UNO_QUERY );
if( xAudio.is() )
{
Any aAny( xAudio->getSource() );
OUString aURL;
if ( ( aAny >>= aURL) && !aURL.isEmpty() )
{
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.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
}
}
nU1 = 1;
nTrigger = 0xb;
nU3 = 0;
{
EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, 2 );
{
EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
rStrm.WriteInt32( nU1 ).WriteInt32( nTrigger ).WriteInt32( nU3 ).WriteInt32( nBegin );
}
}
EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
{
sal_uInt32 const nRefMode = 3;
sal_uInt32 const nRefType = 2;
sal_uInt32 nRefId = mrExSoundCollection.GetId( aURL );
sal_Int32 const begin = -1;
sal_Int32 const end = -1;
EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
rStrm.WriteUInt32( nRefMode ).WriteUInt32( nRefType ).WriteUInt32( nRefId ).WriteInt32( begin ).WriteInt32( end );
}
}
}
exportAnimValue( rStrm, xNode, false );
}
break;
}
if( !bSkipChildren )
{
// export after effect node if one exists for this node
Reference< XAnimationNode > xAfterEffectNode;
if( hasAfterEffectNode( xNode, xAfterEffectNode ) )
{
exportNode( rStrm, xAfterEffectNode, DFF_msofbtAnimSubGoup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
}
Reference< XEnumerationAccess > xEnumerationAccess( xNode, UNO_QUERY );
if( xEnumerationAccess.is() )
{
Reference< XEnumeration > xEnumeration = xEnumerationAccess->createEnumeration();
if( xEnumeration.is() )
{
while( xEnumeration->hasMoreElements() )
{
Reference< XAnimationNode > xChildNode( xEnumeration->nextElement(), UNO_QUERY );
if( xChildNode.is() )
{
if ( xChildNode->getType() == AnimationNodeType::AUDIO )
{
xAudioNode = std::move(xChildNode);
nAudioGroup = mnCurrentGroup;
}
else
exportNode( rStrm, xChildNode, DFF_msofbtAnimGroup, 1, nGroupLevel + 1, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
}
}
}
}
}
}
if ( xAudioNode.is() )
exportNode( rStrm, xAudioNode, DFF_msofbtAnimGroup, 1, nGroupLevel, bTakeBackInteractiveSequenceTimingForChild, nFillDefault );
if( xNode->getType() == AnimationNodeType::ITERATE )
aTarget = Any();
}
Reference< XAnimationNode > AnimationExporter::createAfterEffectNodeClone( const Reference< XAnimationNode >& xNode )
{
try
{
Reference< css::util::XCloneable > xClonable( xNode, UNO_QUERY_THROW );
Reference< XAnimationNode > xCloneNode( xClonable->createClone(), UNO_QUERY_THROW );
Any aEmpty;
xCloneNode->setBegin( aEmpty );
return xCloneNode;
}
catch( Exception& )
{
OSL_FAIL("(@CL)sd::ppt::AnimationExporter::createAfterEffectNodeClone(), could not create clone!" );
}
return xNode;
}
bool AnimationExporter::GetNodeType( const Reference< XAnimationNode >& xNode, sal_Int16& nType )
{
// trying to get the nodetype
const Sequence< NamedValue > aUserData = xNode->getUserData();
for( const NamedValue& rProp : aUserData )
{
if ( rProp.Name == "node-type" )
{
if ( rProp.Value >>= nType )
return true;
}
}
return false;
}
void AnimationExporter::exportAnimNode( SvStream& rStrm, const Reference< XAnimationNode >& xNode,
const sal_Int16 nFillDefault )
{
EscherExAtom aAnimNodeExAtom( rStrm, DFF_msofbtAnimNode );
AnimationNode 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;
}
switch( nFillDefault )
{
default:
case AnimationFill::DEFAULT : aAnim.mnFill = 0; break;
case AnimationFill::REMOVE : aAnim.mnFill = 1; break;
case AnimationFill::FREEZE :
case AnimationFill::HOLD : aAnim.mnFill = 3; break;
case AnimationFill::TRANSITION : aAnim.mnFill = 4; break;
}
// attribute Duration
double fDuration = 0.0;
css::animations::Timing eTiming;
if ( xNode->getDuration() >>= eTiming )
{
if ( eTiming == Timing_INDEFINITE )
aAnim.mnDuration = -1;
}
else if ( xNode->getDuration() >>= fDuration )
{
aAnim.mnDuration = static_cast<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 :
aAnim.mnGroupType = mso_Anim_GroupType_PAR;
[[fallthrough]];
case AnimationNodeType::SEQ :
{
sal_Int16 nType = 0;
if( GetNodeType( xNode, nType ) )
switch( nType )
{
case css::presentation::EffectNodeType::TIMING_ROOT : aAnim.mnNodeType = 0x12; break;
case css::presentation::EffectNodeType::MAIN_SEQUENCE : aAnim.mnNodeType = 0x18; 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;
}
WriteAnimationNode( rStrm, aAnim );
}
void AnimationExporter::GetUserData( const Sequence< NamedValue >& rUserData, const Any ** pAny, std::size_t nLen )
{
// storing user data into pAny, to allow direct access later
memset( pAny, 0, nLen );
if ( !rUserData.hasElements() )
return;
for( const NamedValue& rProp : rUserData )
{
if ( rProp.Name == "node-type" )
{
pAny[ DFF_ANIM_NODE_TYPE ] = &(rProp.Value);
}
else if ( rProp.Name == "preset-class" )
{
pAny[ DFF_ANIM_PRESET_CLASS ] = &(rProp.Value);
}
else if ( rProp.Name == "preset-id" )
{
pAny[ DFF_ANIM_PRESET_ID ] = &(rProp.Value);
}
else if ( rProp.Name == "preset-sub-type" )
{
pAny[ DFF_ANIM_PRESET_SUB_TYPE ] = &(rProp.Value);
}
else if ( rProp.Name == "master-element" )
{
pAny[ DFF_ANIM_AFTEREFFECT ] = &(rProp.Value);
}
}
}
sal_uInt32 AnimationExporter::GetPresetID( std::u16string_view aPreset, sal_uInt32 nAPIPresetClass, bool& bPresetId )
{
sal_uInt32 nPresetId = 0;
bPresetId = false;
if ( o3tl::starts_with(aPreset, u"ppt_") )
{
size_t nLast = aPreset.rfind( '_' );
if ( ( nLast != std::u16string_view::npos ) && ( ( nLast + 1 ) < aPreset.size() ) )
{
std::u16string_view aNumber( aPreset.substr( nLast + 1 ) );
nPresetId = o3tl::toUInt32(aNumber);
bPresetId = true;
}
}
else
{
const oox::ppt::preset_mapping* p = oox::ppt::preset_mapping::getList();
while( p->mpStrPresetId && ((p->mnPresetClass != static_cast<sal_Int32>(nAPIPresetClass)) || !o3tl::equalsAscii(aPreset, p->mpStrPresetId )) )
p++;
if( p->mpStrPresetId )
{
nPresetId = p->mnPresetId;
bPresetId = true;
}
}
return nPresetId;
}
sal_Int16 AnimationExporter::exportAnimPropertySet( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
{
sal_Int16 nNodeType = css::presentation::EffectNodeType::DEFAULT;
EscherExContainer aAnimPropertySet( rStrm, DFF_msofbtAnimPropertySet );
Reference< XAnimationNode > xMaster;
Any aMasterRel, aOverride, aRunTimeContext;
// storing user data into pAny, to allow direct access later
const Sequence< NamedValue > aUserData = xNode->getUserData();
const css::uno::Any* pAny[ DFF_ANIM_PROPERTY_ID_COUNT ];
GetUserData( aUserData, pAny, sizeof( pAny ) );
if( pAny[ DFF_ANIM_AFTEREFFECT ] )
( *pAny[ DFF_ANIM_AFTEREFFECT ] ) >>= xMaster;
// calculate master-rel
if( xMaster.is() )
{
sal_Int32 nMasterRel = 2;
if( xNode.is() && xMaster.is() && (xNode->getParent() == xMaster->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 css::presentation::EffectNodeType::ON_CLICK : nPPTNodeType = DFF_ANIM_NODE_TYPE_ON_CLICK; break;
case css::presentation::EffectNodeType::WITH_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_WITH_PREVIOUS; break;
case css::presentation::EffectNodeType::AFTER_PREVIOUS : nPPTNodeType = DFF_ANIM_NODE_TYPE_AFTER_PREVIOUS; break;
case css::presentation::EffectNodeType::MAIN_SEQUENCE : nPPTNodeType = DFF_ANIM_NODE_TYPE_MAIN_SEQUENCE; break;
case css::presentation::EffectNodeType::TIMING_ROOT : nPPTNodeType = DFF_ANIM_NODE_TYPE_TIMING_ROOT; break;
case css::presentation::EffectNodeType::INTERACTIVE_SEQUENCE: nPPTNodeType = DFF_ANIM_NODE_TYPE_INTERACTIVE_SEQ; break;
}
exportAnimPropertyuInt32( rStrm, DFF_ANIM_NODE_TYPE, nPPTNodeType );
}
}
sal_uInt32 nPresetId = 0;
sal_uInt32 nPresetSubType = 0;
sal_uInt32 nAPIPresetClass = EffectPresetClass::CUSTOM;
sal_uInt32 nPresetClass = DFF_ANIM_PRESS_CLASS_USER_DEFINED;
bool bPresetClass, bPresetId, bPresetSubType;
bPresetId = bPresetClass = bPresetSubType = 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 = true;
}
}
if ( pAny[ DFF_ANIM_PRESET_ID ] )
{
OUString sPreset;
if ( *pAny[ DFF_ANIM_PRESET_ID ] >>= sPreset )
nPresetId = GetPresetID( sPreset, nAPIPresetClass, bPresetId );
}
if ( pAny[ DFF_ANIM_PRESET_SUB_TYPE ] )
{
OUString sPresetSubType;
if ( *pAny[ DFF_ANIM_PRESET_SUB_TYPE ] >>= sPresetSubType )
{
nPresetSubType = TranslatePresetSubType( nPresetClass, nPresetId, sPresetSubType );
bPresetSubType = true;
}
}
if ( bPresetId )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_ID, nPresetId );
if ( bPresetSubType )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_SUB_TYPE, nPresetSubType );
if ( bPresetClass )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_PRESET_CLASS, nPresetClass );
if ( pAny[ DFF_ANIM_ID ] )
{
// TODO DFF_ANIM_ID
}
if ( pAny[ DFF_ANIM_AFTEREFFECT ] )
{
bool bAfterEffect = false;
if ( *pAny[ DFF_ANIM_AFTEREFFECT ] >>= bAfterEffect )
exportAnimPropertyByte( rStrm, DFF_ANIM_AFTEREFFECT, int(bAfterEffect) );
}
if ( pAny[ DFF_ANIM_RUNTIMECONTEXT ] )
{
sal_Int32 nRunTimeContext = 0;
if ( *pAny[ DFF_ANIM_RUNTIMECONTEXT ] >>= nRunTimeContext )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_RUNTIMECONTEXT, nRunTimeContext );
}
if ( pAny[ DFF_ANIM_PATH_EDIT_MODE ] )
{
// TODO DFF_ANIM_ID
}
if( !xMaster.is() )
{
Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
if( xColor.is() )
{
bool bDirection = !xColor->getDirection();
exportAnimPropertyuInt32( rStrm, DFF_ANIM_DIRECTION, bDirection ? 1 : 0 );
}
}
if ( pAny[ DFF_ANIM_OVERRIDE ] )
{
sal_Int32 nOverride = 0;
if ( *pAny[ DFF_ANIM_OVERRIDE ] >>= nOverride )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_OVERRIDE, nOverride );
}
if ( pAny[ DFF_ANIM_MASTERREL ] )
{
sal_Int32 nMasterRel = 0;
if ( *pAny[ DFF_ANIM_MASTERREL ] >>= nMasterRel )
exportAnimPropertyuInt32( rStrm, DFF_ANIM_MASTERREL, nMasterRel );
}
/* 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;
}
bool AnimationExporter::exportAnimProperty( SvStream& rStrm, const sal_uInt16 nPropertyId, const css::uno::Any& rAny, const TranslateMode eTranslateMode )
{
bool bRet = false;
if ( rAny.hasValue() )
{
switch( rAny.getValueTypeClass() )
{
case css::uno::TypeClass_UNSIGNED_SHORT :
case css::uno::TypeClass_SHORT :
case css::uno::TypeClass_UNSIGNED_LONG :
case css::uno::TypeClass_LONG :
{
sal_Int32 nVal = 0;
if ( rAny >>= nVal )
{
exportAnimPropertyuInt32( rStrm, nPropertyId, nVal );
bRet = true;
}
}
break;
case css::uno::TypeClass_DOUBLE :
{
double fVal = 0.0;
if ( rAny >>= fVal )
{
exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
bRet = true;
}
}
break;
case css::uno::TypeClass_FLOAT :
{
float fVal = 0.0;
if ( rAny >>= fVal )
{
if ( eTranslateMode & TRANSLATE_NUMBER_TO_STRING )
{
OUString aNumber( OUString::number( fVal ) );
exportAnimPropertyString( rStrm, nPropertyId, aNumber, eTranslateMode );
}
else
{
exportAnimPropertyFloat( rStrm, nPropertyId, fVal );
bRet = true;
}
}
}
break;
case css::uno::TypeClass_STRING :
{
OUString aStr;
if ( rAny >>= aStr )
{
exportAnimPropertyString( rStrm, nPropertyId, aStr, eTranslateMode );
bRet = true;
}
}
break;
default:
break;
}
}
return bRet;
}
void AnimationExporter::exportAnimPropertyString( SvStream& rStrm, const sal_uInt16 nPropertyId, const OUString& rVal, const TranslateMode eTranslateMode )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_UNISTRING );
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 )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
float fFloat = static_cast<float>(rVal);
rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_FLOAT )
.WriteFloat( fFloat );
}
void AnimationExporter::exportAnimPropertyuInt32( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt32 nVal )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_INT32 )
.WriteUInt32( nVal );
}
void AnimationExporter::exportAnimPropertyByte( SvStream& rStrm, const sal_uInt16 nPropertyId, const sal_uInt8 nVal )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAttributeValue, nPropertyId );
rStrm.WriteUChar( DFF_ANIM_PROP_TYPE_BYTE )
.WriteUChar( nVal );
}
void AnimationExporter::writeZString( SvStream& rStrm, std::u16string_view aVal )
{
for ( size_t i = 0; i < aVal.size(); i++ )
rStrm.WriteUInt16( aVal[ i ] );
rStrm.WriteUInt16( 0 );
}
void AnimationExporter::exportAnimAction( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimAction );
sal_Int32 const nConcurrent = 1;
sal_Int32 const nNextAction = 1;
sal_Int32 nEndSync = 0;
sal_Int32 const nU4 = 0;
sal_Int32 const nU5 = 3;
sal_Int16 nAnimationEndSync = 0;
if ( xNode->getEndSync() >>= nAnimationEndSync )
{
if ( nAnimationEndSync == AnimationEndSync::ALL )
nEndSync = 1;
}
rStrm.WriteInt32( nConcurrent )
.WriteInt32( nNextAction )
.WriteInt32( nEndSync )
.WriteInt32( nU4 )
.WriteInt32( 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;
bool bCreateEvent = false;
Any aSource;
switch( i )
{
case 0 :
case 1 :
{
Any aAny;
Event aEvent;
css::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(), css::uno::UNO_SET_THROW );
if ( 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 INDEFINITE
{
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 = 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 = static_cast<sal_Int32>( fTiming * 1000.0 );
}
aSource = aEvent.Source;
}
else if ( aAny >>= eTiming )
{
bCreateEvent = true;
if ( eTiming == Timing_INDEFINITE )
nBegin = -1;
}
else if ( aAny >>= fTiming )
{
bCreateEvent = true;
nBegin = static_cast<sal_Int32>( fTiming * 1000.0 );
}
}
break;
case 2 :
{
if ( nFlags & ( 1 << i ) )
{
bCreateEvent = true;
nU1 = 1;
nTrigger = 9;
}
}
break;
case 3 :
{
if ( nFlags & ( 1 << i ) )
{
bCreateEvent = true;
nU1 = 1;
nTrigger = 10;
}
}
break;
}
if ( bCreateEvent )
{
EscherExContainer aAnimEvent( rStrm, DFF_msofbtAnimEvent, i + 1 );
{
EscherExAtom aAnimTrigger( rStrm, DFF_msofbtAnimTrigger );
rStrm.WriteInt32( nU1 )
.WriteInt32( nTrigger )
.WriteInt32( nU3 )
.WriteInt32( nBegin );
}
exportAnimateTargetElement( rStrm, aSource, ( nFlags & ( 1 << i ) ) != 0 );
}
}
}
Any AnimationExporter::convertAnimateValue( const Any& rSourceValue, std::u16string_view rAttributeName )
{
OUString aDest;
if ( rAttributeName == u"X"
|| rAttributeName == u"Y"
|| rAttributeName == u"Width"
|| rAttributeName == u"Height"
)
{
OUString aStr;
if ( rSourceValue >>= aStr )
{
ImplTranslateAttribute( aStr, TRANSLATE_MEASURE );
aDest += aStr;
}
}
else if ( rAttributeName == u"Rotate" // "r" or "style.rotation" ?
|| rAttributeName == u"Opacity"
|| rAttributeName == u"CharHeight"
|| rAttributeName == u"SkewX"
)
{
double fNumber = 0.0;
if ( rSourceValue >>= fNumber )
aDest += OUString::number( fNumber );
}
else if ( rAttributeName == u"Color"
|| rAttributeName == u"FillColor" // "Fillcolor" or "FillColor" ?
|| rAttributeName == u"LineColor"
|| rAttributeName == u"CharColor"
)
{
sal_Int32 nColor = 0;
Sequence< double > aHSL( 3 );
OUString aP( u","_ustr );
if ( rSourceValue >>= aHSL )
{
aDest += "hsl("
+ OUString::number( static_cast<sal_Int32>( aHSL[ 0 ] / ( 360.0 / 255 ) ) )
+ aP
+ OUString::number( static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 ) )
+ aP
+ OUString::number( static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 ) )
+ ")";
}
else if ( rSourceValue >>= nColor )
{
aDest += "rgb("
+ OUString::number( static_cast<sal_Int8>(nColor) )
+ aP
+ OUString::number( static_cast<sal_Int8>( nColor >> 8 ) )
+ aP
+ OUString::number( static_cast<sal_Int8>( nColor >> 16 ) )
+ ")";
}
}
else if ( rAttributeName == u"FillStyle" )
{
css::drawing::FillStyle eFillStyle;
if ( rSourceValue >>= eFillStyle )
{
if ( eFillStyle == css::drawing::FillStyle_NONE )
aDest += "none"; // ?
else
aDest += "solid";
}
}
else if (rAttributeName == u"FillOn")
{
bool bFillOn;
if ( rSourceValue >>= bFillOn )
{
if ( bFillOn )
aDest += "true";
else
aDest += "false";
}
}
else if ( rAttributeName == u"LineStyle" )
{
css::drawing::LineStyle eLineStyle;
if ( rSourceValue >>= eLineStyle )
{
if ( eLineStyle == css::drawing::LineStyle_NONE )
aDest += "false";
else
aDest += "true";
}
}
else if ( rAttributeName == u"CharWeight" )
{
float fFontWeight = 0.0;
if ( rSourceValue >>= fFontWeight )
{
if ( fFontWeight == css::awt::FontWeight::BOLD )
aDest += "bold";
else
aDest += "normal";
}
}
else if ( rAttributeName == u"CharUnderline" )
{
sal_Int16 nFontUnderline = 0;
if ( rSourceValue >>= nFontUnderline )
{
if ( nFontUnderline == css::awt::FontUnderline::NONE )
aDest += "false";
else
aDest += "true";
}
}
else if ( rAttributeName == u"CharPosture" )
{
css::awt::FontSlant eFontSlant;
if ( rSourceValue >>= eFontSlant )
{
if ( eFontSlant == css::awt::FontSlant_ITALIC )
aDest += "italic";
else
aDest += "normal"; // ?
}
}
else if ( rAttributeName == u"Visibility" )
{
bool bVisible = true;
if ( rSourceValue >>= bVisible )
{
if ( bVisible )
aDest += "visible";
else
aDest += "hidden";
}
}
Any aRet;
if ( !aDest.isEmpty() )
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() )
return;
EscherExContainer aAnimateSet( rStrm, DFF_msofbtAnimateSet, 0 );
{
EscherExAtom aAnimateSetData( rStrm, DFF_msofbtAnimateSetData );
sal_uInt32 const nId1 = 1; // ??
sal_uInt32 const nId2 = 1; // ??
rStrm.WriteUInt32( nId1 ).WriteUInt32( nId2 );
}
Any aConvertedValue( convertAnimateValue( xSet->getTo(), xSet->getAttributeName() ) );
if ( aConvertedValue.hasValue() )
exportAnimProperty( rStrm, 1, aConvertedValue, TRANSLATE_NONE );
exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
}
sal_uInt32 AnimationExporter::GetValueTypeForAttributeName( std::u16string_view rAttributeName )
{
sal_uInt32 nValueType = 0;
struct Entry
{
const 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 },
{ nullptr, 0 }
};
const Entry* pPtr = &lcl_attributeMap[ 0 ];
while( pPtr->pName )
{
if ( o3tl::equalsIgnoreAsciiCase( rAttributeName, 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() )
return;
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;
sal_uInt32 nValueType = GetValueTypeForAttributeName( xAnimate->getAttributeName() );
if ( aBy.hasValue() )
nBits |= 1;
if ( aFrom.hasValue() )
nBits |= 2;
if ( aTo.hasValue() )
nBits |= 4;
rStrm.WriteUInt32( nCalcMode )
.WriteUInt32( nBits )
.WriteUInt32( 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() )
return;
{
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 const nTransformType = 0;
if ( xAnimate.is() )
{
if ( !xAnimate->getAttributeName().isEmpty() )
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.WriteUInt32( nBits )
.WriteUInt32( nAdditive )
.WriteUInt32( nAccumulate )
.WriteUInt32( nTransformType );
}
if ( !xAnimate->getAttributeName().isEmpty() || nForceAttributeNames )
{
EscherExContainer aAnimateAttributeNames( rStrm, DFF_msofbtAnimateAttributeNames, 1 );
OUString aAttributeName( xAnimate->getAttributeName() );
if ( nForceAttributeNames )
{
if( nForceAttributeNames == 1 )
{
aAttributeName = "r";
}
}
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 );
if( nAfterEffectType == AFTEREFFECT_COLOR )
{
exportAnimPropertyuInt32( rStrm, 4, 0 );
exportAnimPropertyuInt32( rStrm, 5, 0 );
}
}
exportAnimateTargetElement( rStrm, aTarget.hasValue() ? aTarget : xAnimate->getTarget(), false );
}
Reference< XShape > AnimationExporter::getTargetElementShape( const Any& rAny, sal_Int32& rBegin, sal_Int32& rEnd, bool& rParagraphTarget )
{
Reference< XShape > xShape;
rAny >>= xShape;
rParagraphTarget = false;
if( xShape.is() )
return xShape;
ParagraphTarget aParaTarget;
if( rAny >>= aParaTarget )
xShape = aParaTarget.Shape;
if ( !xShape.is() )
return xShape;
// now calculating the character range for the paragraph
sal_Int16 nParagraph = aParaTarget.Paragraph;
Reference< XSimpleText > xText( xShape, UNO_QUERY );
if ( !xText.is() )
return xShape;
rParagraphTarget = true;
Reference< XEnumerationAccess > xTextParagraphEnumerationAccess( xText, UNO_QUERY );
if ( !xTextParagraphEnumerationAccess.is() )
return xShape;
Reference< XEnumeration > xTextParagraphEnumeration( xTextParagraphEnumerationAccess->createEnumeration() );
if ( !xTextParagraphEnumeration.is() )
return xShape;
sal_Int16 nCurrentParagraph;
rBegin = rEnd = nCurrentParagraph = 0;
while ( xTextParagraphEnumeration->hasMoreElements() )
{
Reference< XTextRange > xTextRange( xTextParagraphEnumeration->nextElement(), UNO_QUERY );
if ( xTextRange.is() )
{
OUString aParaText( xTextRange->getString() );
sal_Int32 nLength = aParaText.getLength() + 1;
rEnd += nLength;
if ( nCurrentParagraph == nParagraph )
break;
nCurrentParagraph++;
rBegin += nLength;
}
}
return xShape;
}
void AnimationExporter::exportAnimateTargetElement( SvStream& rStrm, const Any& rAny, const bool bCreate2b01Atom )
{
sal_uInt32 nRefMode = 0; // nRefMode == 2 -> Paragraph
sal_Int32 begin = -1;
sal_Int32 end = -1;
bool bParagraphTarget;
Reference< XShape > xShape = getTargetElementShape(rAny, begin, end, bParagraphTarget);
if( bParagraphTarget )
nRefMode = 2;
if ( !(xShape.is() || bCreate2b01Atom) )
return;
EscherExContainer aAnimateTargetElement( rStrm, DFF_msofbtAnimateTargetElement );
if ( xShape.is() )
{
EscherExAtom aAnimReference( rStrm, DFF_msofbtAnimReference );
sal_uInt32 const nRefType = 1; // TODO: nRefType == 2 -> Sound;
sal_uInt32 nRefId = mrSolverContainer.GetShapeId( xShape );
rStrm.WriteUInt32( nRefMode )
.WriteUInt32( nRefType )
.WriteUInt32( nRefId )
.WriteInt32( begin )
.WriteInt32( end );
}
if ( bCreate2b01Atom )
{
EscherExAtom a2b01Atom( rStrm, 0x2b01 );
rStrm.WriteUInt32( 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.hasElements() )
return;
EscherExContainer aAnimKeyPoints( rStrm, DFF_msofbtAnimKeyPoints );
sal_Int32 i;
for ( i = 0; i < aKeyTimes.getLength(); i++ )
{
{
EscherExAtom aAnimKeyTime( rStrm, DFF_msofbtAnimKeyTime );
sal_Int32 nKeyTime = static_cast<sal_Int32>( aKeyTimes[ i ] * 1000.0 );
rStrm.WriteInt32( 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.isEmpty() )
{
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 bool bExportAlways )
{
Any aAny;
// repeat count (0)
double fRepeat = 0.0;
float fRepeatCount = 0.0;
css::animations::Timing eTiming;
aAny = xNode->getRepeatCount();
if ( aAny >>= eTiming )
{
if ( eTiming == Timing_INDEFINITE )
fRepeatCount = (float(3.40282346638528860e+38));
}
else if ( aAny >>= fRepeat )
fRepeatCount = static_cast<float>(fRepeat);
if ( fRepeatCount != 0.0 )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
sal_uInt32 const nType = 0;
rStrm.WriteUInt32( nType )
.WriteFloat( fRepeatCount );
}
// accelerate (3)
float fAccelerate = static_cast<float>(xNode->getAcceleration());
if ( bExportAlways || ( fAccelerate != 0.0 ) )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
sal_uInt32 const nType = 3;
rStrm.WriteUInt32( nType )
.WriteFloat( fAccelerate );
}
// decelerate (4)
float fDecelerate = static_cast<float>(xNode->getDecelerate());
if ( bExportAlways || ( fDecelerate != 0.0 ) )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
sal_uInt32 const nType = 4;
rStrm.WriteUInt32( nType )
.WriteFloat( fDecelerate );
}
// autoreverse (5)
bool bAutoReverse = xNode->getAutoReverse();
if ( bExportAlways || bAutoReverse )
{
EscherExAtom aExAtom( rStrm, DFF_msofbtAnimValue );
sal_uInt32 const nType = 5;
sal_uInt32 nVal = bAutoReverse ? 1 : 0;
rStrm.WriteUInt32( nType )
.WriteUInt32( nVal );
}
}
void AnimationExporter::exportTransitionFilter( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
{
Reference< XTransitionFilter > xFilter( xNode, UNO_QUERY );
if ( !xFilter.is() )
return;
EscherExContainer aAnimateFilter( rStrm, DFF_msofbtAnimateFilter );
{
EscherExAtom aAnimateFilterData( rStrm, DFF_msofbtAnimateFilterData );
sal_uInt32 const nBits = 3; // bit 0 -> use AnimAttributeValue
// bit 1 -> use nTransition
sal_uInt32 nTransition = xFilter->getMode() ? 0 : 1;
rStrm.WriteUInt32( nBits )
.WriteUInt32( nTransition );
}
const char* pFilter = FindTransitionName( 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() )
return;
EscherExContainer aAnimateMotion( rStrm, DFF_msofbtAnimateMotion );
{
{ //SJ: Ignored from import filter
EscherExAtom aAnimateMotionData( rStrm, DFF_msofbtAnimateMotionData );
sal_uInt32 const nBits = 0x98;
sal_uInt32 const nOrigin = 0x2;
float const fByX = 100.0; // nBits&1
float const fByY = 100.0; // nBits&1
float const fFromX = 0.0; // nBits&2
float const fFromY = 0.0; // nBits&2
float const fToX = 100.0; // nBits&4
float const fToY = 100.0; // nBits&4
rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( nOrigin );
}
OUString aStr;
if ( xMotion->getPath() >>= aStr )
{
if ( !aStr.isEmpty() )
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() )
return;
if ( xTransform->getTransformType() == AnimationTransformType::SCALE )
{
EscherExContainer aAnimateScale( rStrm, DFF_msofbtAnimateScale );
{
EscherExAtom aAnimateScaleData( rStrm, DFF_msofbtAnimateScaleData );
sal_uInt32 nBits = 0;
sal_uInt32 const 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 = static_cast<float>( fX * 100 );
fByY = static_cast<float>( fY * 100 );
}
}
if ( xTransform->getFrom() >>= aPair )
{
if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
{
nBits |= 2;
fFromX = static_cast<float>( fX * 100 );
fFromY = static_cast<float>( fY * 100 );
}
}
if( xTransform->getTo() >>= aPair )
{
if ( ( aPair.First >>= fX ) && ( aPair.Second >>= fY ) )
{
nBits |= 4;
fToX = static_cast<float>( fX * 100 );
fToY = static_cast<float>( fY * 100 );
}
}
// TODO: ZoomContents:
//if( nBits & 8 )
//( fprintf( mpFile, " zoomContents=\"%s\"", nZoomContents ? "true" : "false" );
rStrm.WriteUInt32( nBits ).WriteFloat( fByX ).WriteFloat( fByY ).WriteFloat( fFromX ).WriteFloat( fFromY ).WriteFloat( fToX ).WriteFloat( fToY ).WriteUInt32( 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 const 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 = static_cast<float>(fVal);
}
if ( xTransform->getFrom() >>= fVal )
{
nBits |= 2;
fFrom = static_cast<float>(fVal);
}
if ( xTransform->getTo() >>= fVal )
{
nBits |= 4;
fTo = static_cast<float>(fVal);
}
rStrm.WriteUInt32( nBits ).WriteFloat( fBy ).WriteFloat( fFrom ).WriteFloat( fTo ).WriteUInt32( nU1 );
}
exportAnimateTarget( rStrm, xNode, 1 );
}
}
bool AnimationExporter::getColorAny( const Any& rAny, const sal_Int16 nColorSpace, sal_Int32& rMode, sal_Int32& rA, sal_Int32& rB, sal_Int32& rC )
{
bool bIsColor = true;
rMode = 0;
if ( nColorSpace == AnimationColorSpace::HSL )
rMode = 1;
sal_Int32 nColor = 0;
Sequence< double > aHSL( 3 );
if ( rAny >>= nColor ) // RGB color
{
rA = static_cast<sal_uInt8>( nColor >> 16 );
rB = static_cast<sal_uInt8>( nColor >> 8 );
rC = static_cast<sal_uInt8>(nColor);
}
else if ( rAny >>= aHSL ) // HSL
{
rA = static_cast<sal_Int32>( aHSL[ 0 ] * 255.0 / 360.0 );
rB = static_cast<sal_Int32>( aHSL[ 1 ] * 255.0 );
rC = static_cast<sal_Int32>( aHSL[ 2 ] * 255.0 );
}
else
bIsColor = false;
return bIsColor;
}
void AnimationExporter::exportAnimateColor( SvStream& rStrm, const Reference< XAnimationNode >& xNode, int nAfterEffectType )
{
Reference< XAnimateColor > xColor( xNode, UNO_QUERY );
if ( !xColor.is() )
return;
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 .WriteUInt32( nBits )
.WriteInt32( nByMode ).WriteInt32( nByA ).WriteInt32( nByB ).WriteInt32( nByC )
.WriteInt32( nFromMode ).WriteInt32( nFromA ).WriteInt32( nFromB ).WriteInt32( nFromC )
.WriteInt32( nToMode ).WriteInt32( nToA ).WriteInt32( nToB ).WriteInt32( nToC );
}
exportAnimateTarget( rStrm, xNode, 0, nAfterEffectType );
}
void AnimationExporter::exportIterate( SvStream& rStrm, const Reference< XAnimationNode >& xNode )
{
Reference< XIterateContainer > xIterate( xNode, UNO_QUERY );
if ( !xIterate.is() )
return;
EscherExAtom aAnimIteration( rStrm, DFF_msofbtAnimIteration );
float fInterval = 10.0;
sal_Int32 nTextUnitEffect = 0;
sal_Int32 const nU1 = 1;
sal_Int32 const nU2 = 1;
sal_Int32 const nU3 = 0xe;
sal_Int16 nIterateType = xIterate->getIterateType();
switch( nIterateType )
{
case TextAnimationType::BY_WORD : nTextUnitEffect = 1; break;
case TextAnimationType::BY_LETTER : nTextUnitEffect = 2; break;
}
fInterval = static_cast<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();
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 = static_cast<float>(100.0 * fInterval / fDuration);
rStrm.WriteFloat( fInterval ).WriteInt32( nTextUnitEffect ).WriteInt32( nU1 ).WriteInt32( nU2 ).WriteInt32( nU3 );
aTarget = xIterate->getTarget();
}
} // namespace ppt;
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V547 Expression is always false.
↑ V614 Uninitialized variable 'eTiming' used.
↑ V1019 Compound assignment expression 'aPair.Second >>= fY' is used inside condition.
↑ V1019 Compound assignment expression 'aPair.Second >>= fY' is used inside condition.
↑ V1019 Compound assignment expression 'aPair.Second >>= fY' is used inside condition.