1042 lines
38 KiB
C++
1042 lines
38 KiB
C++
/* -*- 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 <oox/ppt/timenodelistcontext.hxx>
|
|
|
|
#include <rtl/math.hxx>
|
|
#include <sal/log.hxx>
|
|
#include <comphelper/diagnose_ex.hxx>
|
|
|
|
#include <com/sun/star/animations/AnimationTransformType.hpp>
|
|
#include <com/sun/star/animations/AnimationCalcMode.hpp>
|
|
#include <com/sun/star/animations/AnimationColorSpace.hpp>
|
|
#include <com/sun/star/animations/AnimationNodeType.hpp>
|
|
#include <com/sun/star/animations/ValuePair.hpp>
|
|
#include <com/sun/star/presentation/EffectCommands.hpp>
|
|
#include <com/sun/star/beans/NamedValue.hpp>
|
|
|
|
#include <oox/helper/attributelist.hxx>
|
|
#include <oox/core/xmlfilterbase.hxx>
|
|
#include <oox/drawingml/drawingmltypes.hxx>
|
|
#include <drawingml/colorchoicecontext.hxx>
|
|
#include <oox/ppt/slidetransition.hxx>
|
|
#include <oox/token/namespaces.hxx>
|
|
#include <oox/token/tokens.hxx>
|
|
#include <o3tl/string_view.hxx>
|
|
#include <utility>
|
|
|
|
#include "animvariantcontext.hxx"
|
|
#include "commonbehaviorcontext.hxx"
|
|
#include "conditioncontext.hxx"
|
|
#include "commontimenodecontext.hxx"
|
|
#include "timeanimvaluecontext.hxx"
|
|
#include "animationtypes.hxx"
|
|
#include "timetargetelementcontext.hxx"
|
|
|
|
using namespace ::oox::core;
|
|
using namespace ::oox::drawingml;
|
|
using namespace ::com::sun::star;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::animations;
|
|
using namespace ::com::sun::star::presentation;
|
|
using namespace ::com::sun::star::xml::sax;
|
|
using ::com::sun::star::beans::NamedValue;
|
|
|
|
namespace {
|
|
|
|
oox::ppt::AnimationAttributeEnum getAttributeEnumByAPIName(std::u16string_view rAPIName)
|
|
{
|
|
oox::ppt::AnimationAttributeEnum eResult = oox::ppt::AnimationAttributeEnum::UNKNOWN;
|
|
const oox::ppt::ImplAttributeNameConversion *attrConv = oox::ppt::getAttributeConversionList();
|
|
while(attrConv->mpAPIName != nullptr)
|
|
{
|
|
if(o3tl::equalsAscii(rAPIName, attrConv->mpAPIName))
|
|
{
|
|
eResult = attrConv->meAttribute;
|
|
break;
|
|
}
|
|
attrConv++;
|
|
}
|
|
return eResult;
|
|
}
|
|
|
|
bool convertAnimationValueWithTimeNode(const oox::ppt::TimeNodePtr& pNode, css::uno::Any &rAny)
|
|
{
|
|
css::uno::Any aAny = pNode->getNodeProperties()[oox::ppt::NP_ATTRIBUTENAME];
|
|
OUString aNameList;
|
|
aAny >>= aNameList;
|
|
|
|
// only get first token.
|
|
return oox::ppt::convertAnimationValue(getAttributeEnumByAPIName(o3tl::getToken(aNameList, 0, ';')), rAny);
|
|
}
|
|
|
|
css::uno::Any convertPointPercent(const css::awt::Point& rPoint)
|
|
{
|
|
css::animations::ValuePair aPair;
|
|
// rPoint.X and rPoint.Y are in 1000th of a percent, but we only need ratio.
|
|
aPair.First <<= static_cast<double>(rPoint.X) / 100000.0;
|
|
aPair.Second <<= static_cast<double>(rPoint.Y) / 100000.0;
|
|
return Any(aPair);
|
|
}
|
|
}
|
|
|
|
namespace oox::ppt {
|
|
|
|
namespace {
|
|
|
|
struct AnimColor
|
|
{
|
|
AnimColor(sal_Int16 cs, sal_Int32 o, sal_Int32 t, sal_Int32 th )
|
|
: colorSpace( cs ), one( o ), two( t ), three( th )
|
|
{
|
|
}
|
|
|
|
Any get() const
|
|
{
|
|
sal_Int32 nColor;
|
|
Any aColor;
|
|
|
|
switch( colorSpace )
|
|
{
|
|
case AnimationColorSpace::HSL:
|
|
aColor <<= Sequence< double >{ one / 100000.0, two / 100000.0, three / 100000.0 };
|
|
break;
|
|
case AnimationColorSpace::RGB:
|
|
nColor = ( ( ( one * 128 ) / 1000 ) & 0xff ) << 16
|
|
| ( ( ( two * 128 ) / 1000 ) & 0xff ) << 8
|
|
| ( ( ( three * 128 ) / 1000 ) & 0xff );
|
|
aColor <<= nColor;
|
|
break;
|
|
default:
|
|
nColor = 0;
|
|
aColor <<= nColor;
|
|
break;
|
|
}
|
|
return aColor;
|
|
}
|
|
|
|
sal_Int16 colorSpace;
|
|
sal_Int32 one;
|
|
sal_Int32 two;
|
|
sal_Int32 three;
|
|
};
|
|
|
|
/** CT_TLMediaNodeAudio
|
|
CT_TLMediaNodeVideo */
|
|
class MediaNodeContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
MediaNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
, mbIsNarration( false )
|
|
, mbFullScrn( false )
|
|
, mbHideDuringShow(false)
|
|
{
|
|
AttributeList attribs( xAttribs );
|
|
|
|
switch( aElement )
|
|
{
|
|
case PPT_TOKEN( audio ):
|
|
mbIsNarration = attribs.getBool( XML_isNarration, false );
|
|
break;
|
|
case PPT_TOKEN( video ):
|
|
mbFullScrn = attribs.getBool( XML_fullScrn, false );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void onEndElement() override
|
|
{
|
|
sal_Int32 aElement = getCurrentElement();
|
|
if( aElement == PPT_TOKEN( audio ) )
|
|
{
|
|
mpNode->getNodeProperties()[NP_ISNARRATION] <<= mbIsNarration;
|
|
}
|
|
else if( aElement == PPT_TOKEN( video ) )
|
|
{
|
|
// TODO deal with mbFullScrn
|
|
}
|
|
else if (aElement == PPT_TOKEN(cMediaNode))
|
|
{
|
|
mpNode->getNodeProperties()[NP_HIDEDURINGSHOW] <<= mbHideDuringShow;
|
|
}
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cTn ):
|
|
return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
|
|
case PPT_TOKEN( tgtEl ):
|
|
return new TimeTargetElementContext( *this, mpNode->getTarget() );
|
|
case PPT_TOKEN(cMediaNode):
|
|
mbHideDuringShow = !rAttribs.getBool(XML_showWhenStopped, true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
private:
|
|
bool mbIsNarration;
|
|
bool mbFullScrn;
|
|
bool mbHideDuringShow;
|
|
};
|
|
|
|
/** CT_TLSetBehavior
|
|
*/
|
|
class SetTimeNodeContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
SetTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
|
|
}
|
|
|
|
virtual ~SetTimeNodeContext() noexcept override
|
|
{
|
|
if(maTo.hasValue())
|
|
{
|
|
convertAnimationValueWithTimeNode(mpNode, maTo);
|
|
mpNode->setTo(maTo);
|
|
}
|
|
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( to ):
|
|
// CT_TLAnimVariant
|
|
return new AnimVariantContext( *this, aElementToken, maTo );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
Any maTo;
|
|
};
|
|
|
|
/** CT_TLCommandBehavior
|
|
*/
|
|
class CmdTimeNodeContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
CmdTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
, maType(0)
|
|
{
|
|
switch ( aElement )
|
|
{
|
|
case PPT_TOKEN( cmd ):
|
|
msCommand = xAttribs->getOptionalValue( XML_cmd );
|
|
maType = xAttribs->getOptionalValueToken( XML_type, 0 );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
virtual void onEndElement() override
|
|
{
|
|
if( !isCurrentElement( PPT_TOKEN( cmd ) ) )
|
|
return;
|
|
|
|
try {
|
|
// see sd/source/filter/ppt/pptinanimations.cxx
|
|
// in AnimationImporter::importCommandContainer()
|
|
// REFACTOR?
|
|
// a good chunk of this code has been copied verbatim *sigh*
|
|
sal_Int16 nCommand = EffectCommands::CUSTOM;
|
|
NamedValue aParamValue;
|
|
|
|
switch( maType )
|
|
{
|
|
case XML_verb:
|
|
aParamValue.Name = "Verb";
|
|
// TODO make sure msCommand has what we want
|
|
aParamValue.Value <<= msCommand.toInt32();
|
|
nCommand = EffectCommands::VERB;
|
|
break;
|
|
case XML_evt:
|
|
case XML_call:
|
|
if ( msCommand == "onstopaudio" )
|
|
{
|
|
nCommand = EffectCommands::STOPAUDIO;
|
|
}
|
|
else if ( msCommand == "play" )
|
|
{
|
|
nCommand = EffectCommands::PLAY;
|
|
}
|
|
else if (msCommand.startsWith("playFrom"))
|
|
{
|
|
std::u16string_view aMediaTime( msCommand.subView( 9, msCommand.getLength() - 10 ) );
|
|
rtl_math_ConversionStatus eStatus;
|
|
double fMediaTime = ::rtl::math::stringToDouble( aMediaTime, u'.', u',', &eStatus );
|
|
if( eStatus == rtl_math_ConversionStatus_Ok )
|
|
{
|
|
aParamValue.Name = "MediaTime";
|
|
aParamValue.Value <<= fMediaTime;
|
|
}
|
|
nCommand = EffectCommands::PLAY;
|
|
}
|
|
else if ( msCommand == "togglePause" )
|
|
{
|
|
nCommand = EffectCommands::TOGGLEPAUSE;
|
|
}
|
|
else if ( msCommand == "stop" )
|
|
{
|
|
nCommand = EffectCommands::STOP;
|
|
}
|
|
break;
|
|
}
|
|
mpNode->getNodeProperties()[ NP_COMMAND ] <<= nCommand;
|
|
if( nCommand == EffectCommands::CUSTOM )
|
|
{
|
|
SAL_WARN("oox.ppt", "OOX: CmdTimeNodeContext::endFastElement(), unknown command!");
|
|
aParamValue.Name = "UserDefined";
|
|
aParamValue.Value <<= msCommand;
|
|
}
|
|
if( aParamValue.Value.hasValue() )
|
|
{
|
|
Sequence< NamedValue > aParamSeq( &aParamValue, 1 );
|
|
mpNode->getNodeProperties()[ NP_PARAMETER ] <<= aParamSeq;
|
|
}
|
|
}
|
|
catch( RuntimeException& )
|
|
{
|
|
TOOLS_WARN_EXCEPTION("oox.ppt", "OOX: Exception in CmdTimeNodeContext::endFastElement()" );
|
|
}
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
private:
|
|
OUString msCommand;
|
|
sal_Int32 maType;
|
|
};
|
|
|
|
/** CT_TLTimeNodeSequence
|
|
*/
|
|
class SequenceTimeNodeContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
SequenceTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
, mnNextAc(0)
|
|
, mnPrevAc(0)
|
|
{
|
|
AttributeList attribs(xAttribs);
|
|
mbConcurrent = attribs.getBool( XML_concurrent, false );
|
|
mnNextAc = xAttribs->getOptionalValueToken( XML_nextAc, 0 );
|
|
mnPrevAc = xAttribs->getOptionalValueToken( XML_prevAc, 0 );
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cTn ):
|
|
return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
|
|
case PPT_TOKEN( nextCondLst ):
|
|
return new CondListContext( *this, aElementToken, mpNode, mpNode->getNextCondition() );
|
|
case PPT_TOKEN( prevCondLst ):
|
|
return new CondListContext( *this, aElementToken, mpNode, mpNode->getPrevCondition() );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
bool mbConcurrent;
|
|
sal_Int32 mnNextAc, mnPrevAc;
|
|
};
|
|
|
|
/** CT_TLTimeNodeParallel
|
|
* CT_TLTimeNodeExclusive
|
|
*/
|
|
class ParallelExclTimeNodeContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
ParallelExclTimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cTn ):
|
|
return new CommonTimeNodeContext( *this, aElementToken, rAttribs.getFastAttributeList(), mpNode );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
protected:
|
|
|
|
};
|
|
|
|
/** CT_TLAnimateColorBehavior */
|
|
class AnimColorContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimColorContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode ) noexcept
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
, mnColorSpace( xAttribs->getOptionalValueToken( XML_clrSpc, 0 ) )
|
|
, mnDir( xAttribs->getOptionalValueToken( XML_dir, 0 ) )
|
|
, mbHasByColor( false )
|
|
, m_byColor( AnimationColorSpace::RGB, 0, 0, 0)
|
|
{
|
|
}
|
|
|
|
virtual void onEndElement() override
|
|
{
|
|
//xParentNode
|
|
if( !isCurrentElement( mnElement ) )
|
|
return;
|
|
|
|
NodePropertyMap & rProps(mpNode->getNodeProperties());
|
|
rProps[ NP_DIRECTION ] <<= mnDir == XML_cw;
|
|
rProps[ NP_COLORINTERPOLATION ] <<= mnColorSpace == XML_hsl ? AnimationColorSpace::HSL : AnimationColorSpace::RGB;
|
|
const GraphicHelper& rGraphicHelper = getFilter().getGraphicHelper();
|
|
if( maToClr.isUsed() )
|
|
mpNode->setTo( Any( maToClr.getColor( rGraphicHelper ) ) );
|
|
if( maFromClr.isUsed() )
|
|
mpNode->setFrom( Any( maFromClr.getColor( rGraphicHelper ) ) );
|
|
if( mbHasByColor )
|
|
mpNode->setBy( m_byColor.get() );
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( hsl ):
|
|
// CT_TLByHslColorTransform
|
|
{
|
|
if( mbHasByColor )
|
|
{
|
|
m_byColor.colorSpace = AnimationColorSpace::HSL;
|
|
m_byColor.one = rAttribs.getInteger( XML_h, 0 );
|
|
m_byColor.two = rAttribs.getInteger( XML_s, 0 );
|
|
m_byColor.three = rAttribs.getInteger( XML_l, 0 );
|
|
}
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( rgb ):
|
|
{
|
|
if( mbHasByColor )
|
|
{
|
|
// CT_TLByRgbColorTransform
|
|
m_byColor.colorSpace = AnimationColorSpace::RGB;
|
|
m_byColor.one = rAttribs.getInteger( XML_r, 0 );
|
|
m_byColor.two = rAttribs.getInteger( XML_g, 0 );
|
|
m_byColor.three = rAttribs.getInteger( XML_b, 0 );
|
|
}
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( by ):
|
|
// CT_TLByAnimateColorTransform
|
|
mbHasByColor = true;
|
|
return this;
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( to ):
|
|
// CT_Color
|
|
return new ColorContext( *this, maToClr );
|
|
case PPT_TOKEN( from ):
|
|
// CT_Color
|
|
return new ColorContext( *this, maFromClr );
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
private:
|
|
sal_Int32 mnColorSpace;
|
|
sal_Int32 mnDir;
|
|
bool mbHasByColor;
|
|
AnimColor m_byColor;
|
|
oox::drawingml::Color maToClr;
|
|
oox::drawingml::Color maFromClr;
|
|
};
|
|
|
|
/** CT_TLAnimateBehavior */
|
|
class AnimContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode ) noexcept
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
NodePropertyMap & aProps( pNode->getNodeProperties() );
|
|
sal_Int32 nCalcMode = xAttribs->getOptionalValueToken( XML_calcmode, 0 );
|
|
if(nCalcMode)
|
|
{
|
|
sal_Int16 nEnum = 0;
|
|
switch(nCalcMode)
|
|
{
|
|
case XML_lin:
|
|
nEnum = AnimationCalcMode::LINEAR;
|
|
break;
|
|
case XML_discrete:
|
|
case XML_fmla:
|
|
default:
|
|
// TODO what value is good ?
|
|
nEnum = AnimationCalcMode::DISCRETE;
|
|
break;
|
|
}
|
|
aProps[ NP_CALCMODE ] <<= nEnum;
|
|
}
|
|
|
|
msFrom = xAttribs->getOptionalValue(XML_from);
|
|
msTo = xAttribs->getOptionalValue(XML_to);
|
|
msBy = xAttribs->getOptionalValue(XML_by);
|
|
|
|
mnValueType = xAttribs->getOptionalValueToken( XML_valueType, 0 );
|
|
}
|
|
|
|
virtual ~AnimContext() noexcept override
|
|
{
|
|
if (!msFrom.isEmpty())
|
|
{
|
|
css::uno::Any aAny;
|
|
aAny <<= msFrom;
|
|
convertAnimationValueWithTimeNode(mpNode, aAny);
|
|
mpNode->setFrom(aAny);
|
|
}
|
|
|
|
if (!msTo.isEmpty())
|
|
{
|
|
css::uno::Any aAny;
|
|
aAny <<= msTo;
|
|
convertAnimationValueWithTimeNode(mpNode, aAny);
|
|
mpNode->setTo(aAny);
|
|
}
|
|
|
|
if (!msBy.isEmpty())
|
|
{
|
|
css::uno::Any aAny;
|
|
aAny <<= msBy;
|
|
convertAnimationValueWithTimeNode(mpNode, aAny);
|
|
mpNode->setBy(aAny);
|
|
}
|
|
|
|
int nKeyTimes = maTavList.size();
|
|
if( nKeyTimes <= 0)
|
|
return;
|
|
|
|
int i=0;
|
|
Sequence< double > aKeyTimes( nKeyTimes );
|
|
auto pKeyTimes = aKeyTimes.getArray();
|
|
Sequence< Any > aValues( nKeyTimes );
|
|
auto pValues = aValues.getArray();
|
|
|
|
NodePropertyMap & aProps( mpNode->getNodeProperties() );
|
|
for (auto const& tav : maTavList)
|
|
{
|
|
// TODO what to do if it is Timing_INFINITE ?
|
|
Any aTime = GetTimeAnimateValueTime( tav.msTime );
|
|
aTime >>= pKeyTimes[i];
|
|
pValues[i] = tav.maValue;
|
|
convertAnimationValueWithTimeNode(mpNode, pValues[i]);
|
|
|
|
// Examine pptx documents and find that only the first tav
|
|
// has the formula set. The formula can be used for the whole.
|
|
if (!tav.msFormula.isEmpty())
|
|
{
|
|
OUString sFormula = tav.msFormula;
|
|
(void)convertMeasure(sFormula);
|
|
aProps[NP_FORMULA] <<= sFormula;
|
|
}
|
|
|
|
++i;
|
|
}
|
|
aProps[ NP_VALUES ] <<= aValues;
|
|
aProps[ NP_KEYTIMES ] <<= aKeyTimes;
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( tavLst ):
|
|
return new TimeAnimValueListContext ( *this, maTavList );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
sal_Int32 mnValueType;
|
|
TimeAnimationValueList maTavList;
|
|
OUString msFrom;
|
|
OUString msTo;
|
|
OUString msBy;
|
|
};
|
|
|
|
/** CT_TLAnimateScaleBehavior */
|
|
class AnimScaleContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimScaleContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode )
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
, mbZoomContents( false )
|
|
{
|
|
AttributeList attribs( xAttribs );
|
|
// TODO what to do with mbZoomContents
|
|
mbZoomContents = attribs.getBool( XML_zoomContents, false );
|
|
pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
|
|
<<= sal_Int16(AnimationTransformType::SCALE);
|
|
}
|
|
|
|
virtual void onEndElement() override
|
|
{
|
|
if( !isCurrentElement( mnElement ) )
|
|
return;
|
|
|
|
if( maTo.hasValue() )
|
|
{
|
|
mpNode->setTo( maTo );
|
|
}
|
|
if( maBy.hasValue() )
|
|
{
|
|
mpNode->setBy( maBy );
|
|
}
|
|
if( maFrom.hasValue() )
|
|
{
|
|
mpNode->setFrom( maFrom );
|
|
}
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( to ):
|
|
{
|
|
// CT_TLPoint
|
|
maTo = convertPointPercent(GetPointPercent(rAttribs.getFastAttributeList()));
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( from ):
|
|
{
|
|
// CT_TLPoint
|
|
maFrom = convertPointPercent(GetPointPercent(rAttribs.getFastAttributeList()));
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( by ):
|
|
{
|
|
// CT_TLPoint
|
|
css::awt::Point aPoint = GetPointPercent(rAttribs.getFastAttributeList());
|
|
// We got ending values instead of offset values, so subtract 100% from them.
|
|
aPoint.X -= 100000;
|
|
aPoint.Y -= 100000;
|
|
maBy = convertPointPercent(aPoint);
|
|
return this;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
Any maBy;
|
|
Any maFrom;
|
|
Any maTo;
|
|
bool mbZoomContents;
|
|
};
|
|
|
|
/** CT_TLAnimateRotationBehavior */
|
|
class AnimRotContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimRotContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode ) noexcept
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
AttributeList attribs( xAttribs );
|
|
|
|
pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
|
|
<<= sal_Int16(AnimationTransformType::ROTATE);
|
|
// see also DFF_msofbtAnimateRotationData in
|
|
// sd/source/filter/ppt/pptinanimations.cxx
|
|
if(attribs.hasAttribute( XML_by ) )
|
|
{
|
|
double fBy = attribs.getDouble( XML_by, 0.0 ) / PER_DEGREE; //1 PowerPoint-angle-unit = 1/60000 degree
|
|
pNode->setBy( Any( fBy ) );
|
|
}
|
|
if(attribs.hasAttribute( XML_from ) )
|
|
{
|
|
double fFrom = attribs.getDouble( XML_from, 0.0 ) / PER_DEGREE;
|
|
pNode->setFrom( Any( fFrom ) );
|
|
}
|
|
if(attribs.hasAttribute( XML_to ) )
|
|
{
|
|
double fTo = attribs.getDouble( XML_to, 0.0 ) / PER_DEGREE;
|
|
pNode->setTo( Any( fTo ) );
|
|
}
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
};
|
|
|
|
/** CT_TLAnimateMotionBehavior */
|
|
class AnimMotionContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimMotionContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode ) noexcept
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
pNode->getNodeProperties()[ NP_TRANSFORMTYPE ]
|
|
<<= sal_Int16(AnimationTransformType::TRANSLATE);
|
|
|
|
AttributeList attribs( xAttribs );
|
|
sal_Int32 nOrigin = xAttribs->getOptionalValueToken( XML_origin, 0 );
|
|
if( nOrigin != 0 )
|
|
{
|
|
switch(nOrigin)
|
|
{
|
|
case XML_layout:
|
|
case XML_parent:
|
|
break;
|
|
}
|
|
// TODO
|
|
}
|
|
|
|
OUString aStr = xAttribs->getOptionalValue( XML_path );
|
|
// E can appear inside a number, so we only check for its presence at the end
|
|
aStr = aStr.trim();
|
|
if (aStr.endsWith("E"))
|
|
aStr = aStr.copy(0, aStr.getLength() - 1);
|
|
aStr = aStr.trim();
|
|
pNode->getNodeProperties()[ NP_PATH ] <<= aStr;
|
|
mnPathEditMode = xAttribs->getOptionalValueToken( XML_pathEditMode, 0 );
|
|
msPtsTypes = xAttribs->getOptionalValue( XML_ptsTypes );
|
|
mnAngle = attribs.getInteger( XML_rAng, 0 );
|
|
// TODO make sure the units are right. Likely not.
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( to ):
|
|
{
|
|
// CT_TLPoint
|
|
awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
|
|
Any rAny;
|
|
rAny <<= p.X;
|
|
rAny <<= p.Y;
|
|
mpNode->setTo( rAny );
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( from ):
|
|
{
|
|
// CT_TLPoint
|
|
awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
|
|
Any rAny;
|
|
rAny <<= p.X;
|
|
rAny <<= p.Y;
|
|
mpNode->setFrom( rAny );
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( by ):
|
|
{
|
|
// CT_TLPoint
|
|
awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
|
|
Any rAny;
|
|
rAny <<= p.X;
|
|
rAny <<= p.Y;
|
|
mpNode->setBy( rAny );
|
|
return this;
|
|
}
|
|
case PPT_TOKEN( rCtr ):
|
|
{
|
|
// CT_TLPoint
|
|
awt::Point p = GetPointPercent( rAttribs.getFastAttributeList() );
|
|
// TODO push
|
|
(void)p;
|
|
return this;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
OUString msPtsTypes;
|
|
sal_Int32 mnPathEditMode;
|
|
sal_Int32 mnAngle;
|
|
};
|
|
|
|
/** CT_TLAnimateEffectBehavior */
|
|
class AnimEffectContext
|
|
: public TimeNodeContext
|
|
{
|
|
public:
|
|
AnimEffectContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode ) noexcept
|
|
: TimeNodeContext( rParent, aElement, pNode )
|
|
{
|
|
sal_Int32 nDir = xAttribs->getOptionalValueToken( XML_transition, 0 );
|
|
OUString sFilter = xAttribs->getOptionalValue( XML_filter );
|
|
// TODO
|
|
// OUString sPrList = xAttribs->getOptionalValue( XML_prLst );
|
|
|
|
if( !sFilter.isEmpty() )
|
|
{
|
|
SlideTransition aFilter( sFilter );
|
|
aFilter.setMode( nDir != XML_out );
|
|
pNode->setTransitionFilter( aFilter );
|
|
}
|
|
}
|
|
|
|
virtual ::oox::core::ContextHandlerRef onCreateContext( sal_Int32 aElementToken, const AttributeList& /*rAttribs*/ ) override
|
|
{
|
|
switch ( aElementToken )
|
|
{
|
|
case PPT_TOKEN( cBhvr ):
|
|
return new CommonBehaviorContext ( *this, mpNode );
|
|
case PPT_TOKEN( progress ):
|
|
return new AnimVariantContext( *this, aElementToken, maProgress );
|
|
// TODO handle it.
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
private:
|
|
Any maProgress;
|
|
};
|
|
|
|
}
|
|
|
|
rtl::Reference<TimeNodeContext> TimeNodeContext::makeContext(
|
|
FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
const Reference< XFastAttributeList >& xAttribs,
|
|
const TimeNodePtr & pNode )
|
|
{
|
|
rtl::Reference<TimeNodeContext> pCtx;
|
|
switch( aElement )
|
|
{
|
|
case PPT_TOKEN( animClr ):
|
|
pCtx = new AnimColorContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( seq ):
|
|
pCtx = new SequenceTimeNodeContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( par ):
|
|
case PPT_TOKEN( excl ):
|
|
pCtx = new ParallelExclTimeNodeContext( rParent, aElement, pNode );
|
|
break;
|
|
case PPT_TOKEN( anim ):
|
|
pCtx = new AnimContext ( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( animEffect ):
|
|
pCtx = new AnimEffectContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( animMotion ):
|
|
pCtx = new AnimMotionContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( animRot ):
|
|
pCtx = new AnimRotContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( animScale ):
|
|
pCtx = new AnimScaleContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( cmd ):
|
|
pCtx = new CmdTimeNodeContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
case PPT_TOKEN( set ):
|
|
pCtx = new SetTimeNodeContext( rParent, aElement, pNode );
|
|
break;
|
|
case PPT_TOKEN( audio ):
|
|
case PPT_TOKEN( video ):
|
|
pCtx = new MediaNodeContext( rParent, aElement, xAttribs, pNode );
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return pCtx;
|
|
}
|
|
|
|
TimeNodeContext::TimeNodeContext( FragmentHandler2 const & rParent, sal_Int32 aElement,
|
|
TimeNodePtr pNode ) noexcept
|
|
: FragmentHandler2( rParent )
|
|
, mnElement( aElement )
|
|
, mpNode(std::move( pNode ))
|
|
{
|
|
}
|
|
|
|
TimeNodeContext::~TimeNodeContext( ) noexcept
|
|
{
|
|
|
|
}
|
|
|
|
TimeNodeListContext::TimeNodeListContext( FragmentHandler2 const & rParent, TimeNodePtrList & aList )
|
|
noexcept
|
|
: FragmentHandler2( rParent )
|
|
, maList( aList )
|
|
{
|
|
}
|
|
|
|
TimeNodeListContext::~TimeNodeListContext( ) noexcept
|
|
{
|
|
}
|
|
|
|
::oox::core::ContextHandlerRef TimeNodeListContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
|
|
{
|
|
sal_Int16 nNodeType;
|
|
|
|
switch( aElementToken )
|
|
{
|
|
case PPT_TOKEN( seq ):
|
|
nNodeType = AnimationNodeType::SEQ;
|
|
break;
|
|
case PPT_TOKEN( par ):
|
|
case PPT_TOKEN( excl ):
|
|
// TODO pick the right type. We choose parallel for now as
|
|
// there does not seem to be an "Exclusive"
|
|
nNodeType = AnimationNodeType::PAR;
|
|
break;
|
|
case PPT_TOKEN( anim ):
|
|
nNodeType = AnimationNodeType::ANIMATE;
|
|
break;
|
|
case PPT_TOKEN( animClr ):
|
|
nNodeType = AnimationNodeType::ANIMATECOLOR;
|
|
break;
|
|
case PPT_TOKEN( animEffect ):
|
|
nNodeType = AnimationNodeType::TRANSITIONFILTER;
|
|
break;
|
|
case PPT_TOKEN( animMotion ):
|
|
nNodeType = AnimationNodeType::ANIMATEMOTION;
|
|
break;
|
|
case PPT_TOKEN( animRot ):
|
|
case PPT_TOKEN( animScale ):
|
|
nNodeType = AnimationNodeType::ANIMATETRANSFORM;
|
|
break;
|
|
case PPT_TOKEN( cmd ):
|
|
nNodeType = AnimationNodeType::COMMAND;
|
|
break;
|
|
case PPT_TOKEN( set ):
|
|
nNodeType = AnimationNodeType::SET;
|
|
break;
|
|
case PPT_TOKEN( audio ):
|
|
nNodeType = AnimationNodeType::AUDIO;
|
|
break;
|
|
case PPT_TOKEN( video ):
|
|
nNodeType = AnimationNodeType::AUDIO;
|
|
SAL_WARN("oox.ppt", "OOX: video requested, gave Audio instead" );
|
|
break;
|
|
|
|
default:
|
|
nNodeType = AnimationNodeType::CUSTOM;
|
|
SAL_INFO("oox.ppt", "unhandled token " << aElementToken);
|
|
break;
|
|
}
|
|
|
|
TimeNodePtr pNode = std::make_shared<TimeNode>(nNodeType);
|
|
maList.push_back( pNode );
|
|
rtl::Reference<FragmentHandler2> pContext = TimeNodeContext::makeContext( *this, aElementToken, rAttribs.getFastAttributeList(), pNode );
|
|
|
|
return pContext ? pContext : this;
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|