diff options
Diffstat (limited to 'xmloff/source/draw/animationimport.cxx')
-rw-r--r-- | xmloff/source/draw/animationimport.cxx | 1315 |
1 files changed, 1315 insertions, 0 deletions
diff --git a/xmloff/source/draw/animationimport.cxx b/xmloff/source/draw/animationimport.cxx new file mode 100644 index 000000000..84d4407c8 --- /dev/null +++ b/xmloff/source/draw/animationimport.cxx @@ -0,0 +1,1315 @@ +/* -*- 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 <memory> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/animations/AnimationTransformType.hpp> +#include <com/sun/star/animations/XAnimationNodeSupplier.hpp> +#include <com/sun/star/animations/AnimationNodeType.hpp> +#include <com/sun/star/animations/SequenceTimeContainer.hpp> +#include <com/sun/star/animations/XIterateContainer.hpp> +#include <com/sun/star/animations/XAnimateMotion.hpp> +#include <com/sun/star/animations/XAnimateColor.hpp> +#include <com/sun/star/animations/XAnimateTransform.hpp> +#include <com/sun/star/animations/XTransitionFilter.hpp> +#include <com/sun/star/animations/XCommand.hpp> +#include <com/sun/star/animations/XAudio.hpp> +#include <com/sun/star/animations/ValuePair.hpp> +#include <com/sun/star/animations/AnimationColorSpace.hpp> +#include <com/sun/star/presentation/EffectPresetClass.hpp> +#include <com/sun/star/animations/Timing.hpp> +#include <com/sun/star/animations/Event.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/xml/sax/XFastAttributeList.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/text/XTextRangeCompare.hpp> +#include <com/sun/star/presentation/ParagraphTarget.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/animations/EventTrigger.hpp> +#include <com/sun/star/presentation/EffectCommands.hpp> +#include <com/sun/star/util/Duration.hpp> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> + +#include <sal/log.hxx> +#include <sax/tools/converter.hxx> + +#include <vector> + +#include <xmloff/xmltypes.hxx> +#include "sdpropls.hxx" +#include <xmloff/xmltoken.hxx> +#include <xmloff/xmlimp.hxx> +#include <xmloff/xmlnmspe.hxx> +#include <xmloff/xmluconv.hxx> +#include <osl/diagnose.h> +#include <xmloff/nmspmap.hxx> +#include <xmloff/xmlprhdl.hxx> +#include <facreg.hxx> +#include <xmlsdtypes.hxx> + +#include <animations.hxx> +#include <animationimport.hxx> + +using namespace ::std; +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::animations; +using namespace ::com::sun::star::presentation; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::uno; +using namespace ::xmloff::token; + +using ::com::sun::star::xml::sax::XFastAttributeList; +using ::com::sun::star::beans::NamedValue; +using ::com::sun::star::text::XTextRange; +using ::com::sun::star::text::XTextCursor; +using ::com::sun::star::text::XTextRangeCompare; +using ::com::sun::star::container::XEnumerationAccess; +using ::com::sun::star::container::XEnumeration; +using ::com::sun::star::lang::XInitialization; + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + return "vnd.sun.star.Package:" + rURL; + + return rImport.GetAbsoluteReference(rURL); +} + +namespace xmloff +{ + +class AnimationsImportHelperImpl +{ +private: + SvXMLImport& mrImport; + +public: + explicit AnimationsImportHelperImpl( SvXMLImport& rImport ); + + Any convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ); + Sequence< Any > convertValueSequence( XMLTokenEnum eAttributeName, const OUString& rValue ); + + Any convertTarget( const OUString& rValue ); + static Any convertPath( const OUString& rValue ); + Any convertTiming( const OUString& rValue ); + static Sequence< double > convertKeyTimes( const OUString& rValue ); + static Sequence< TimeFilterPair > convertTimeFilter( const OUString& rValue ); +}; + +AnimationsImportHelperImpl::AnimationsImportHelperImpl( SvXMLImport& rImport ) +: mrImport( rImport ) +{ +} + +static bool isDouble( const OUString& rValue ) +{ + sal_Int32 nLength = rValue.getLength(); + const sal_Unicode * pStr = rValue.getStr(); + while( nLength ) + { + if( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) + { + pStr++; + nLength--; + } + else + { + return false; + } + } + + return true; +} + +static bool isTime( const OUString& rValue ) +{ + sal_Int32 nLength = rValue.getLength(); + const sal_Unicode * pStr; + for( pStr = rValue.getStr(); nLength; pStr++, nLength-- ) + { + if( !( (*pStr >= '0' && *pStr <= '9') || *pStr == '-' || *pStr == '.' || *pStr == '+' || *pStr == 'e' || *pStr == 'E' ) ) + break; + } + + // return true if this is a double (if someone forgot the 's' we silently ignore it) + // or if it's a double that ends with a 's' or 'S' + return (nLength == 0) || ((*pStr == 's' || *pStr == 'S') && (nLength == 1)); +} + +Any AnimationsImportHelperImpl::convertTarget( const OUString& rValue ) +{ + try + { + Reference< XInterface > xRef( mrImport.getInterfaceToIdentifierMapper().getReference( rValue ) ); + + Reference< XShape > _xShape( xRef, UNO_QUERY ); + if( _xShape.is() ) + return makeAny( _xShape ); + + Reference< XTextCursor > xTextCursor( xRef, UNO_QUERY ); + if( xTextCursor.is() ) + { + Reference< XTextRange > xStart( xTextCursor->getStart() ), xRange; + Reference< XShape > xShape( xTextCursor->getText(), UNO_QUERY_THROW ); + Reference< XTextRangeCompare > xTextRangeCompare( xShape, UNO_QUERY_THROW ); + + Reference< XEnumerationAccess > xParaEnumAccess( xShape, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xParaEnumAccess->createEnumeration(), UNO_SET_THROW ); + sal_Int16 nParagraph = 0; + + while( xEnumeration->hasMoreElements() ) + { + xEnumeration->nextElement() >>= xRange; + + // break if start of selection is prior to end of current paragraph + if( xRange.is() && (xTextRangeCompare->compareRegionEnds( xStart, xRange ) >= 0 ) ) + { + return makeAny( ParagraphTarget( xShape, nParagraph ) ); + } + + nParagraph++; + } + } + } + catch (const RuntimeException&) + { + OSL_FAIL( "xmloff::AnimationsImportImpl::convertTarget(), RuntimeException caught!" ); + } + + Any aAny; + return aAny; +} + +Any AnimationsImportHelperImpl::convertValue( XMLTokenEnum eAttributeName, const OUString& rValue ) +{ + sal_Int32 nCommaPos = -1, nPos; + sal_Int32 nOpenBrakets = 0; + for( nPos = 0; (nPos < rValue.getLength()) && (nCommaPos == -1); nPos++ ) + { + switch( rValue[nPos] ) + { + case ',': + if( nOpenBrakets == 0 ) + nCommaPos = nPos; + break; + case '(': + case '[': + case '{': + nOpenBrakets++; + break; + case ')': + case ']': + case '}': + nOpenBrakets--; + break; + } + } + + if( nCommaPos >= 0 ) + { + ValuePair aPair; + aPair.First = convertValue( eAttributeName, rValue.copy( 0, nCommaPos ) ); + aPair.Second = convertValue( eAttributeName, rValue.copy( nCommaPos+1 ) ); + return makeAny( aPair ); + } + else + { + Any aAny; + sal_Int32 nType = XML_TYPE_STRING; + + if( rValue.getLength() ) switch( eAttributeName ) + { + case XML_X: + case XML_Y: + case XML_WIDTH: + case XML_HEIGHT: + case XML_TRANSLATE: + { + return makeAny( rValue ); + } + + case XML_SCALE: + case XML_SKEWY: + case XML_SKEWX: + case XML_OPACITY: + case XML_ROTATE: nType = XML_TYPE_DOUBLE; break; + case XML_TEXT_ROTATION_ANGLE:nType = XML_TYPE_TEXT_ROTATION_ANGLE; break; + case XML_FILL_COLOR: + case XML_STROKE_COLOR: + case XML_DIM: + case XML_COLOR: nType = XML_TYPE_COLOR; break; + case XML_FILL: nType = XML_SD_TYPE_FILLSTYLE; break; + case XML_STROKE: nType = XML_SD_TYPE_STROKE; break; + case XML_FONT_WEIGHT: nType = XML_TYPE_TEXT_WEIGHT; break; + case XML_FONT_STYLE: nType = XML_TYPE_TEXT_POSTURE; break; + case XML_TEXT_UNDERLINE: nType = XML_TYPE_TEXT_UNDERLINE_STYLE; break; + case XML_FONT_SIZE: nType = XML_TYPE_DOUBLE_PERCENT; break; + case XML_VISIBILITY: nType = XML_SD_TYPE_PRESPAGE_VISIBILITY; break; + + default: + if( !rValue.isEmpty() ) + aAny <<= rValue; + return aAny; + } + + const XMLPropertyHandler* pHandler = mrImport.GetShapeImport()->GetSdPropHdlFactory()->GetPropertyHandler( nType ); + if( pHandler ) + pHandler->importXML( rValue, aAny, mrImport.GetMM100UnitConverter() ); + + return aAny; + } +} + +Sequence< Any > AnimationsImportHelperImpl::convertValueSequence( XMLTokenEnum eAttributeName, const OUString& rValue ) +{ + Sequence< Any > aValues; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + // prepare the sequence + aValues.realloc( nElements ); + + // fill the sequence + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertValue( eAttributeName, rValue.getToken( 0, ';', nIndex ) ); + } + + return aValues; +} + +Any AnimationsImportHelperImpl::convertTiming( const OUString& rValue ) +{ + Any aAny; + + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + if ( nElements>0 ) + { + if( nElements == 1 ) + { + if( IsXMLToken( rValue, XML_MEDIA ) ) + { + aAny <<= Timing_MEDIA; + } + else if( IsXMLToken( rValue, XML_INDEFINITE ) ) + { + aAny <<= Timing_INDEFINITE; + } + else if( isTime( rValue ) ) + { + aAny <<= rValue.toDouble(); + } + else + { + Event aEvent; + aEvent.Repeat = 0; + aEvent.Trigger = 0; + + OUString aEventTrigger; + + sal_Int32 nPos = rValue.indexOf( '+' ); + if( nPos == -1 ) + { + aEventTrigger = rValue; + } + else + { + aEventTrigger = rValue.copy( 0, nPos ); + + // convert offset + aEvent.Offset = convertTiming( rValue.copy( nPos + 1 ) ); + } + + nPos = aEventTrigger.indexOf( '.' ); + if( nPos != -1 ) + { + aEvent.Source <<= mrImport.getInterfaceToIdentifierMapper().getReference( aEventTrigger.copy( 0, nPos ) ); + aEventTrigger = aEventTrigger.copy( nPos + 1 ); + } + + sal_Int16 nEnum; + if( SvXMLUnitConverter::convertEnum( nEnum, aEventTrigger, aAnimations_EnumMap_EventTrigger ) ) + { + aEvent.Trigger = nEnum; + } + else + { + OSL_FAIL("AnimationsImportHelperImpl::convertTiming(), unknown event trigger!"); + } + + aAny <<= aEvent; + } + } + else + { + // fill the sequence + Sequence< Any > aValues( nElements ); + Any* pValues = aValues.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = convertTiming( rValue.getToken( 0, ';', nIndex ) ); + + aAny <<= aValues; + } + } + return aAny; +} + +Sequence< double > AnimationsImportHelperImpl::convertKeyTimes( const OUString& rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< double > aKeyTimes( nElements ); + + if( nElements ) + { + double* pValues = aKeyTimes.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + *pValues++ = rValue.getToken( 0, ';', nIndex ).toDouble(); + } + + return aKeyTimes; +} + +Sequence< TimeFilterPair > AnimationsImportHelperImpl::convertTimeFilter( const OUString& rValue ) +{ + const sal_Int32 nElements { comphelper::string::getTokenCount(rValue, ';') }; + + Sequence< TimeFilterPair > aTimeFilter( nElements ); + + if( nElements ) + { + TimeFilterPair* pValues = aTimeFilter.getArray(); + for (sal_Int32 nIndex = 0; nIndex >= 0; ) + { + const OUString aToken( rValue.getToken( 0, ';', nIndex ) ); + + sal_Int32 nPos = aToken.indexOf( ',' ); + if( nPos >= 0 ) + { + pValues->Time = aToken.copy( 0, nPos ).toDouble(); + pValues->Progress = aToken.copy( nPos+1 ).toDouble(); + } + pValues++; + } + } + + return aTimeFilter; +} + +Any AnimationsImportHelperImpl::convertPath( const OUString& rValue ) +{ + return makeAny( rValue ); +} + + +AnimationNodeContext::AnimationNodeContext( + const Reference< XAnimationNode >& xParentNode, + SvXMLImport& rImport, sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + const std::shared_ptr<AnimationsImportHelperImpl>& pHelper ) +: SvXMLImportContext(rImport), + mpHelper( pHelper ) +{ + bool bRootContext = !pHelper; + try + { + if( bRootContext ) + { + mpHelper = std::make_shared<AnimationsImportHelperImpl>( rImport ); + mxNode = xParentNode; + } + else + { + sal_Int16 nPresetClass = EffectPresetClass::CUSTOM; + + const char* pServiceName = nullptr; + + // we see namespace ANIMATION and ANIMATION_OOO and PRESENTATION_OASIS and PRESENTATION_SO52 and PRESENTATION_OOO + switch( nElement & TOKEN_MASK ) + { + case XML_SEQ: + pServiceName = "com.sun.star.animations.SequenceTimeContainer"; break; + case XML_ITERATE: + pServiceName = "com.sun.star.animations.IterateContainer"; break; + case XML_ANIMATE: + pServiceName = "com.sun.star.animations.Animate"; break; + case XML_SET: + pServiceName = "com.sun.star.animations.AnimateSet"; break; + case XML_ANIMATEMOTION: + pServiceName = "com.sun.star.animations.AnimateMotion"; break; + case XML_ANIMATECOLOR: + pServiceName = "com.sun.star.animations.AnimateColor"; break; + case XML_ANIMATETRANSFORM: + pServiceName = "com.sun.star.animations.AnimateTransform"; break; + case XML_TRANSITIONFILTER: + pServiceName = "com.sun.star.animations.TransitionFilter"; break; + case XML_AUDIO: + pServiceName = "com.sun.star.animations.Audio"; break; + case XML_COMMAND: + pServiceName = "com.sun.star.animations.Command"; break; + case XML_PAR: + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + if( (aIter.getToken() & TOKEN_MASK) == XML_PRESET_ID) + { + const OUString& rValue = aIter.toString(); + if ( rValue == "ooo-entrance-random" ) + { + nPresetClass = EffectPresetClass::ENTRANCE; + } + else if ( rValue == "ooo-exit-random" ) + { + nPresetClass = EffectPresetClass::EXIT; + } + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + pServiceName = "com.sun.star.comp.sd.RandomAnimationNode"; + break; + } + } + } + if( !pServiceName ) + pServiceName = "com.sun.star.animations.ParallelTimeContainer"; + } + break; + default: + SAL_WARN("xmloff", "unexpected token '" + SvXMLImport::getNameFromToken(nElement) + << "' 0x" << std::hex << nElement); + break; + } + + if( pServiceName ) + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + mxNode.set( + xContext->getServiceManager()->createInstanceWithContext(OUString::createFromAscii(pServiceName), xContext), + UNO_QUERY_THROW ); + + if( nPresetClass != EffectPresetClass::CUSTOM ) + { + Reference< XInitialization > xInit( mxNode, UNO_QUERY_THROW ); + const Any aAny( makeAny( nPresetClass ) ); + Sequence< Any > aArgs( &aAny, 1 ) ; + xInit->initialize( aArgs ); + } + + init_node( xAttrList ); + + Reference< XTimeContainer > xParentContainer( xParentNode, UNO_QUERY_THROW ); + xParentContainer->appendChild( mxNode ); + } + } + } + catch (const RuntimeException&) + { + OSL_FAIL( "xmloff::AnimationsImportImpl::AnimationsImportImpl(), RuntimeException caught!" ); + } +} + +void AnimationNodeContext::startFastElement( sal_Int32 /*nElement*/, const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) +{ + // code of StartElement is moved to init_node that is now called + // in c'tor before appending this node to its parent. + // This is needed for random nodes that need the correct target + // set when child nodes are appended. +} + +void AnimationNodeContext::init_node( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxNode.is() ) try + { + const sal_Int16 nNodeType = mxNode->getType(); + + // query for optional interfaces that are often used later + Reference< XAnimate > xAnimate( mxNode, UNO_QUERY ); + Reference< XCommand > xCommand( mxNode, UNO_QUERY ); + Reference< XTransitionFilter > xTransitionFilter( mxNode, UNO_QUERY ); + Reference< XIterateContainer > xIter( mxNode, UNO_QUERY ); + + std::vector< NamedValue > aUserData; + XMLTokenEnum meAttributeName = XML_TOKEN_INVALID; + OUString aFrom, aBy, aTo, aValues; + bool bHaveXmlId( false ); + OUString sXmlId; + + sal_Int16 nEnum; + for (auto &aIter : sax_fastparser::castToFastAttributeList( xAttrList )) + { + OUString rValue = aIter.toString(); + auto nToken = aIter.getToken(); + switch( nToken ) + { + case XML_ELEMENT(SMIL, XML_BEGIN): + case XML_ELEMENT(SMIL_COMPAT, XML_BEGIN): + case XML_ELEMENT(SMIL_SO52, XML_BEGIN): + { + mxNode->setBegin( mpHelper->convertTiming( rValue ) ); + } + break; + case XML_ELEMENT(SMIL, XML_DUR): + case XML_ELEMENT(SMIL_COMPAT, XML_DUR): + case XML_ELEMENT(SMIL_SO52, XML_DUR): + { + mxNode->setDuration( mpHelper->convertTiming( rValue ) ); + } + break; + case XML_ELEMENT(SMIL, XML_END): + case XML_ELEMENT(SMIL_COMPAT, XML_END): + case XML_ELEMENT(SMIL_SO52, XML_END): + { + mxNode->setEnd( mpHelper->convertTiming( rValue ) ); + } + break; + case XML_ELEMENT(SMIL, XML_FILL): + case XML_ELEMENT(SMIL_COMPAT, XML_FILL): + case XML_ELEMENT(SMIL_SO52, XML_FILL): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_Fill ) ) + mxNode->setFill( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_FILLDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_FILLDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_FillDefault ) ) + mxNode->setFillDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTART): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTART): + case XML_ELEMENT(SMIL_SO52, XML_RESTART): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_Restart ) ) + mxNode->setRestart( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_COMPAT, XML_RESTARTDEFAULT): + case XML_ELEMENT(SMIL_SO52, XML_RESTARTDEFAULT): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_RestartDefault ) ) + mxNode->setRestartDefault( nEnum ); + } + break; + case XML_ELEMENT(SMIL, XML_ACCELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCELERATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCELERATE): + { + if( isDouble( rValue ) ) + mxNode->setAcceleration( rValue.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_DECELERATE): + case XML_ELEMENT(SMIL_COMPAT, XML_DECELERATE): + case XML_ELEMENT(SMIL_SO52, XML_DECELERATE): + { + if( isDouble( rValue ) ) + mxNode->setDecelerate( rValue.toDouble() ); + } + break; + case XML_ELEMENT(SMIL, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_COMPAT, XML_AUTOREVERSE): + case XML_ELEMENT(SMIL_SO52, XML_AUTOREVERSE): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, rValue )) + mxNode->setAutoReverse( bTemp ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATCOUNT): + case XML_ELEMENT(SMIL_SO52, XML_REPEATCOUNT): + { + mxNode->setRepeatCount( mpHelper->convertTiming( rValue ) ); + } + break; + case XML_ELEMENT(SMIL, XML_REPEATDUR): + case XML_ELEMENT(SMIL_COMPAT, XML_REPEATDUR): + case XML_ELEMENT(SMIL_SO52, XML_REPEATDUR): + { + mxNode->setRepeatDuration( mpHelper->convertTiming( rValue ) ); + } + break; + case XML_ELEMENT(SMIL, XML_ENDSYNC): + case XML_ELEMENT(SMIL_COMPAT, XML_ENDSYNC): + case XML_ELEMENT(SMIL_SO52, XML_ENDSYNC): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_Endsync ) ) + mxNode->setEndSync( makeAny( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_NODE_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_NODE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_EffectNodeType ) ) + aUserData.emplace_back( GetXMLToken( XML_NODE_TYPE ), makeAny( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_ID): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_ID): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_ID ), makeAny( rValue ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_SUB_TYPE): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_SUB_TYPE): + { + aUserData.emplace_back( GetXMLToken( XML_PRESET_SUB_TYPE ), makeAny( rValue ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_SO52, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OOO, XML_PRESET_CLASS): + case XML_ELEMENT(PRESENTATION_OASIS, XML_PRESET_CLASS): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_EffectPresetClass ) ) + aUserData.emplace_back( GetXMLToken( XML_PRESET_CLASS ), makeAny( nEnum ) ); + } + break; + case XML_ELEMENT(PRESENTATION, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_SO52, XML_AFTER_EFFECT): + case XML_ELEMENT(PRESENTATION_OOO, XML_AFTER_EFFECT): + { + bool bTemp; + if (::sax::Converter::convertBool( bTemp, rValue )) + aUserData.emplace_back( GetXMLToken( XML_AFTER_EFFECT ), makeAny( bTemp ) ); + } + break; + case XML_ELEMENT(XLINK, XML_HREF): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setSource( makeAny(lcl_GetMediaReference(GetImport(), rValue)) ); + break; + } + [[fallthrough]]; + } + case XML_ELEMENT(SMIL, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_COMPAT, XML_TARGETELEMENT): + case XML_ELEMENT(SMIL_SO52, XML_TARGETELEMENT): + { + Any aTarget( mpHelper->convertTarget( rValue ) ); + + if( xAnimate.is() ) + { + xAnimate->setTarget( aTarget ); + } + else if( xIter.is() ) + { + xIter->setTarget( aTarget ); + } + else if( xCommand.is() ) + { + xCommand->setTarget( aTarget ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_AUDIO_LEVEL): + case XML_ELEMENT(ANIMATION_OOO, XML_AUDIO_LEVEL): + { + if( nNodeType == AnimationNodeType::AUDIO ) + { + if( isDouble( rValue ) ) + { + Reference< XAudio > xAudio( mxNode, UNO_QUERY_THROW ); + xAudio->setVolume( rValue.toDouble() ); + } + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_SO52, XML_MASTER_ELEMENT): + case XML_ELEMENT(PRESENTATION_OOO, XML_MASTER_ELEMENT): + { + Reference< XAnimationNode > xMaster( GetImport().getInterfaceToIdentifierMapper().getReference( rValue ), UNO_QUERY ); + aUserData.emplace_back( GetXMLToken( XML_MASTER_ELEMENT ), makeAny( xMaster ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_SUB_ITEM): + case XML_ELEMENT(ANIMATION_OOO, XML_SUB_ITEM): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_SubItem ) ) + { + if( xAnimate.is() ) + { + xAnimate->setSubItem( nEnum ); + } + else if( xIter.is() ) + { + xIter->setSubItem( nEnum ); + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_COMPAT, XML_ATTRIBUTENAME): + case XML_ELEMENT(SMIL_SO52, XML_ATTRIBUTENAME): + { + if( xAnimate.is() ) + { + OUString aName( rValue ); + + const struct ImplAttributeNameConversion* p = getAnimationAttributeNamesConversionList(); + while( p->mpAPIName ) + { + if( IsXMLToken( aName, p->meXMLToken ) ) + { + aName = OUString::createFromAscii( p->mpAPIName ); + meAttributeName = p->meXMLToken; + break; + } + + p++; + } + + xAnimate->setAttributeName( aName ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_VALUES): + case XML_ELEMENT(SMIL_COMPAT, XML_VALUES): + case XML_ELEMENT(SMIL_SO52, XML_VALUES): + { + aValues = rValue; + } + break; + + case XML_ELEMENT(SMIL, XML_FROM): + case XML_ELEMENT(SMIL_COMPAT, XML_FROM): + case XML_ELEMENT(SMIL_SO52, XML_FROM): + { + aFrom = rValue; + } + break; + + case XML_ELEMENT(SMIL, XML_BY): + case XML_ELEMENT(SMIL_COMPAT, XML_BY): + case XML_ELEMENT(SMIL_SO52, XML_BY): + { + aBy = rValue; + } + break; + + case XML_ELEMENT(SMIL, XML_TO): + case XML_ELEMENT(SMIL_COMPAT, XML_TO): + case XML_ELEMENT(SMIL_SO52, XML_TO): + { + aTo = rValue; + } + break; + + case XML_ELEMENT(SMIL, XML_KEYTIMES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYTIMES): + case XML_ELEMENT(SMIL_SO52, XML_KEYTIMES): + { + if( xAnimate.is() ) + xAnimate->setKeyTimes( AnimationsImportHelperImpl::convertKeyTimes( rValue ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_FORMULA): + case XML_ELEMENT(ANIMATION_OOO, XML_FORMULA): + { + if( xAnimate.is() ) + xAnimate->setFormula( rValue ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_ID): + case XML_ELEMENT(ANIMATION_OOO, XML_ID): + { + if (!bHaveXmlId) { sXmlId = rValue; } + } + break; + case XML_ELEMENT(XML, XML_ID): + { + sXmlId = rValue; + bHaveXmlId = true; + } + break; + + case XML_ELEMENT(SMIL, XML_CALCMODE): + case XML_ELEMENT(SMIL_COMPAT, XML_CALCMODE): + case XML_ELEMENT(SMIL_SO52, XML_CALCMODE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_CalcMode ) ) + xAnimate->setCalcMode( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_COMPAT, XML_ACCUMULATE): + case XML_ELEMENT(SMIL_SO52, XML_ACCUMULATE): + { + if( xAnimate.is() ) + xAnimate->setAccumulate( IsXMLToken( rValue, XML_SUM ) ); + } + break; + + case XML_ELEMENT(PRESENTATION, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_SO52, XML_ADDITIVE): + case XML_ELEMENT(PRESENTATION_OOO, XML_ADDITIVE): + case XML_ELEMENT(SMIL, XML_ADDITIVE): + case XML_ELEMENT(SMIL_COMPAT, XML_ADDITIVE): + case XML_ELEMENT(SMIL_SO52, XML_ADDITIVE): + { + if( xAnimate.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_AdditiveMode ) ) + xAnimate->setAdditive( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_COMPAT, XML_KEYSPLINES): + case XML_ELEMENT(SMIL_SO52, XML_KEYSPLINES): + { + if( xAnimate.is() ) + xAnimate->setTimeFilter( AnimationsImportHelperImpl::convertTimeFilter( rValue ) ); + } + break; + + case XML_ELEMENT(SVG, XML_PATH): + case XML_ELEMENT(SVG_COMPAT, XML_PATH): + { + Reference< XAnimateMotion > xAnimateMotion( mxNode, UNO_QUERY ); + if( xAnimateMotion.is() ) + xAnimateMotion->setPath( AnimationsImportHelperImpl::convertPath( rValue ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setColorInterpolation( IsXMLToken( rValue, XML_HSL ) ? AnimationColorSpace::HSL : AnimationColorSpace::RGB ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COLOR_INTERPOLATION_DIRECTION): + case XML_ELEMENT(ANIMATION_OOO, XML_COLOR_INTERPOLATION_DIRECTION): + { + Reference< XAnimateColor > xAnimateColor( mxNode, UNO_QUERY ); + if( xAnimateColor.is() ) + xAnimateColor->setDirection( IsXMLToken( rValue, XML_CLOCKWISE ) ); + } + break; + + case XML_ELEMENT(SVG, XML_TYPE): + case XML_ELEMENT(SVG_COMPAT, XML_TYPE): + { + Reference< XAnimateTransform > xTransform( mxNode, UNO_QUERY ); + if( xTransform.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_TransformType ) ) + { + xTransform->setTransformType( nEnum ); + switch( nEnum ) + { + case AnimationTransformType::SCALE: meAttributeName = XML_SCALE; break; + case AnimationTransformType::ROTATE: meAttributeName = XML_ROTATE; break; + case AnimationTransformType::SKEWX: meAttributeName = XML_SKEWX; break; + case AnimationTransformType::SKEWY: meAttributeName = XML_SKEWY; break; + //case AnimationTransformType::TRANSLATE: + default: + meAttributeName = XML_TRANSLATE; break; + } + } + } + } + break; + + case XML_ELEMENT(SMIL, XML_TYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_TYPE): + case XML_ELEMENT(SMIL_SO52, XML_TYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_TransitionType ) ) + xTransitionFilter->setTransition( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_SUBTYPE): + case XML_ELEMENT(SMIL_COMPAT, XML_SUBTYPE): + case XML_ELEMENT(SMIL_SO52, XML_SUBTYPE): + { + if( xTransitionFilter.is() ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_TransitionSubType ) ) + xTransitionFilter->setSubtype( nEnum ); + } + } + break; + + case XML_ELEMENT(SMIL, XML_MODE): + case XML_ELEMENT(SMIL_COMPAT, XML_MODE): + case XML_ELEMENT(SMIL_SO52, XML_MODE): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setMode( IsXMLToken( rValue, XML_IN ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_DIRECTION): + case XML_ELEMENT(SMIL_COMPAT, XML_DIRECTION): + case XML_ELEMENT(SMIL_SO52, XML_DIRECTION): + { + if( xTransitionFilter.is() ) + xTransitionFilter->setDirection( IsXMLToken( rValue, XML_FORWARD ) ); + } + break; + + case XML_ELEMENT(SMIL, XML_FADECOLOR): + case XML_ELEMENT(SMIL_COMPAT, XML_FADECOLOR): + case XML_ELEMENT(SMIL_SO52, XML_FADECOLOR): + { + if( xTransitionFilter.is() ) + { + sal_Int32 nColor(0); + ::sax::Converter::convertColor(nColor, rValue); + xTransitionFilter->setFadeColor(nColor); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_TYPE): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_TYPE): + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_IterateType ) ) + { + if( xIter.is() ) + xIter->setIterateType( nEnum ); + } + } + break; + + case XML_ELEMENT(ANIMATION, XML_ITERATE_INTERVAL): + case XML_ELEMENT(ANIMATION_OOO, XML_ITERATE_INTERVAL): + { + if( xIter.is() ) + { + double fInterval = 0.0; + if( rValue.match("P") ) + { + css::util::Duration aDuration; + if (::sax::Converter::convertDuration(aDuration, rValue)) + { + fInterval = ((((aDuration.Hours * 60) + + aDuration.Minutes) * 60) + aDuration.Seconds) + + (aDuration.NanoSeconds / 1000000000.0); + } + } + else + { + fInterval = rValue.toDouble(); + } + + xIter->setIterateInterval( fInterval ); + } + } + break; + + case XML_ELEMENT(PRESENTATION, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_SO52, XML_GROUP_ID): + case XML_ELEMENT(PRESENTATION_OOO, XML_GROUP_ID): + { + aUserData.emplace_back( "group-id", makeAny( rValue.toInt32() ) ); + } + break; + + case XML_ELEMENT(ANIMATION, XML_COMMAND): + case XML_ELEMENT(ANIMATION_OOO, XML_COMMAND): + { + if( xCommand.is() && nNodeType == AnimationNodeType::COMMAND ) + { + if( SvXMLUnitConverter::convertEnum( nEnum, rValue, aAnimations_EnumMap_Command ) ) + { + xCommand->setCommand( nEnum ); + } + } + } + break; + + default: + { + // push all unknown attributes within the presentation namespace as user data + if (IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_SO52) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OASIS) + || IsTokenInNamespace(nToken, XML_NAMESPACE_PRESENTATION_OOO)) + { + aUserData.emplace_back( SvXMLImport::getNameFromToken(aIter.getToken()), makeAny( rValue ) ); + } + else + SAL_WARN("xmloff", "unknown token '" + SvXMLImport::getNameFromToken(aIter.getToken()) + << "' 0x" << std::hex << aIter.getToken()); + } + } + } + + if (!sXmlId.isEmpty()) + { + Reference< XInterface > const xRef( mxNode, UNO_QUERY ); + GetImport().getInterfaceToIdentifierMapper().registerReference( + sXmlId, xRef ); + } + + sal_Int32 nUserDataCount = aUserData.size(); + if( nUserDataCount ) + { + Sequence< NamedValue > aUnoUserData( nUserDataCount ); + NamedValue* pData = aUnoUserData.getArray(); + for (auto const& item : aUserData) + *pData++ = item; + + mxNode->setUserData( aUnoUserData ); + } + + // convert values + if( xAnimate.is() ) + { + if( !aFrom.isEmpty() ) + xAnimate->setFrom( mpHelper->convertValue( meAttributeName, aFrom ) ); + + if( !aBy.isEmpty() ) + xAnimate->setBy( mpHelper->convertValue( meAttributeName, aBy ) ); + + if( !aTo.isEmpty() ) + xAnimate->setTo( mpHelper->convertValue( meAttributeName, aTo ) ); + + if( !aValues.isEmpty() ) + xAnimate->setValues( mpHelper->convertValueSequence( meAttributeName, aValues ) ); + + if (xAnimate->getValues().getLength() != xAnimate->getKeyTimes().getLength()) + throw css::io::WrongFormatException(); + } + } + catch (const css::io::WrongFormatException&) + { + throw; + } + catch (const RuntimeException&) + { + OSL_FAIL( "xmloff::AnimationNodeContext::StartElement(), RuntimeException caught!" ); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > AnimationNodeContext::createFastChildContext(sal_Int32 nElement, + const css::uno::Reference<css::xml::sax::XFastAttributeList>& xAttrList) +{ + if( mxNode.is()) + return new AnimationNodeContext( mxNode, GetImport(), nElement, xAttrList, mpHelper ); + return nullptr; +} + +namespace { + +class AnimationsImport: public SvXMLImport, public XAnimationNodeSupplier +{ +public: + explicit AnimationsImport( const Reference< XComponentContext > & rxContext ); + + SvXMLImportContext* CreateFastContext(sal_Int32 nElement, + const Reference<XFastAttributeList>& xAttrList) override; + + // XInterface + virtual Any SAL_CALL queryInterface( const Type& aType ) override; + virtual void SAL_CALL acquire() throw () override; + virtual void SAL_CALL release() throw () override; + + // XAnimationNodeSupplier + Reference< XAnimationNode > SAL_CALL getAnimationNode() override; + +private: + Reference< XAnimationNode > mxRootNode; +}; + +} + +AnimationsImport::AnimationsImport( const Reference< XComponentContext > & rxContext ) +: SvXMLImport( rxContext, "xmloff::AnimationsImport", SvXMLImportFlags::META ) + //FIXME: the above "IMPORT_META" used to be a nonsensical "true", question + // remains whether this should be IMPORT_META (same numerical value as + // true) or default IMPORT_ALL +{ + mxRootNode.set( SequenceTimeContainer::create(rxContext), UNO_QUERY_THROW ); +} + +// XInterface +Any SAL_CALL AnimationsImport::queryInterface( const Type& aType ) +{ + if ( aType == cppu::UnoType<XAnimationNodeSupplier>::get()) + { + return makeAny( Reference<XAnimationNodeSupplier>( this ) ); + } + else + { + return SvXMLImport::queryInterface( aType ); + } +} + +void SAL_CALL AnimationsImport::acquire() throw () +{ + SvXMLImport::acquire(); +} + +void SAL_CALL AnimationsImport::release() throw () +{ + SvXMLImport::release(); +} + +SvXMLImportContext *AnimationsImport::CreateFastContext( + sal_Int32 nElement, + const Reference<XFastAttributeList>& xAttrList) +{ + SvXMLImportContext* pContext = nullptr; + + if( nElement == XML_ELEMENT(ANIMATION, XML_SEQ) || nElement == XML_ELEMENT(ANIMATION_OOO, XML_SEQ) ) + { + pContext = new AnimationNodeContext( mxRootNode, *this, nElement, xAttrList ); + } + + return pContext; +} + +// XAnimationNodeSupplier +Reference< XAnimationNode > SAL_CALL AnimationsImport::getAnimationNode() +{ + return mxRootNode; +} + +void AnimationNodeContext::postProcessRootNode( const Reference< XAnimationNode >& xRootNode, Reference< XPropertySet > const & xPageProps ) +{ + if( xRootNode.is() && xPageProps.is() ) try + { + Reference< XEnumerationAccess > xEnumerationAccess( xRootNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xEnumeration( xEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + if( xEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xNode( xEnumeration->nextElement(), UNO_QUERY_THROW ); + if( xNode->getType() == AnimationNodeType::PAR ) + { + Event aEvent; + if( (xNode->getBegin() >>= aEvent) && (aEvent.Trigger == EventTrigger::BEGIN_EVENT) ) + { + // found transition node + Reference< XEnumerationAccess > xChildEnumerationAccess( xNode, UNO_QUERY_THROW ); + Reference< XEnumeration > xChildEnumeration( xChildEnumerationAccess->createEnumeration(), UNO_SET_THROW ); + while( xChildEnumeration->hasMoreElements() ) + { + Reference< XAnimationNode > xChildNode( xChildEnumeration->nextElement(), UNO_QUERY_THROW ); + switch( xChildNode->getType() ) + { + case AnimationNodeType::TRANSITIONFILTER: + { + Reference< XTransitionFilter > xTransFilter( xChildNode, UNO_QUERY_THROW ); + + xPageProps->setPropertyValue("TransitionType", Any( xTransFilter->getTransition() ) ); + xPageProps->setPropertyValue("TransitionSubtype", Any( xTransFilter->getSubtype() ) ); + xPageProps->setPropertyValue("TransitionDirection", Any( xTransFilter->getDirection() ) ); + xPageProps->setPropertyValue("TransitionFadeColor", Any( xTransFilter->getFadeColor() ) ); + + double fDuration; + if( xTransFilter->getDuration() >>= fDuration ) + xPageProps->setPropertyValue("TransitionDuration", Any( fDuration ) ); + + } + break; + + case AnimationNodeType::COMMAND: + { + Reference< XCommand > xCommand( xChildNode, UNO_QUERY_THROW ); + if( xCommand->getCommand() == EffectCommands::STOPAUDIO ) + { + xPageProps->setPropertyValue("Sound", Any(true) ); + } + } + break; + + case AnimationNodeType::AUDIO: + { + Reference< XAudio > xAudio( xChildNode, UNO_QUERY_THROW ); + OUString sSoundURL; + if( (xAudio->getSource() >>= sSoundURL) && !sSoundURL.isEmpty() ) + { + xPageProps->setPropertyValue("Sound", Any(sSoundURL) ); + + Timing eTiming; + if( (xAudio->getRepeatCount() >>= eTiming) && (eTiming == Timing_INDEFINITE) ) + xPageProps->setPropertyValue("LoopSound", Any( true ) ); + } + } + break; + + } + } + + Reference< XTimeContainer > xRootContainer( xRootNode, UNO_QUERY_THROW ); + xRootContainer->removeChild( xNode ); + } + } + } + } + catch (const Exception&) + { + OSL_FAIL("xmloff::AnimationsImport::postProcessRootNode(), exception caught!"); + } +} + +} // namespace xmloff + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_Xmloff_AnimationsImport(uno::XComponentContext* pCtx, + uno::Sequence<uno::Any> const& /*rSeq*/) +{ + return cppu::acquire(new xmloff::AnimationsImport(pCtx)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |