sd/pptx-anmiations refactor NodeContext.

Change-Id: I6439882884b3808dec91eaaede50856b0afdd278
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146293
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Mark Hung 2023-01-27 23:34:49 +08:00 committed by Noel Grandin
parent 000d88c53a
commit 55d4dc3a6b
4 changed files with 250 additions and 182 deletions

View file

@ -188,6 +188,7 @@ $(eval $(call gb_Library_add_exception_objects,sd,\
sd/source/filter/eppt/pptx-epptooxml \
sd/source/filter/eppt/pptx-animations \
sd/source/filter/eppt/pptx-animations-cond \
sd/source/filter/eppt/pptx-animations-nodectx \
sd/source/filter/eppt/pptx-grouptable \
sd/source/filter/eppt/pptx-stylesheet \
sd/source/filter/eppt/pptx-text \

View file

@ -0,0 +1,188 @@
/* -*- 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/.
*/
#include "pptx-animations-nodectx.hxx"
#include <com/sun/star/animations/AnimationNodeType.hpp>
#include <com/sun/star/animations/XAnimate.hpp>
#include <com/sun/star/animations/XAnimationNode.hpp>
#include <com/sun/star/animations/XCommand.hpp>
#include <com/sun/star/animations/XAudio.hpp>
#include <com/sun/star/animations/XIterateContainer.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/container/XEnumeration.hpp>
#include <com/sun/star/presentation/EffectNodeType.hpp>
#include <com/sun/star/presentation/EffectPresetClass.hpp>
#include <com/sun/star/presentation/ParagraphTarget.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <o3tl/any.hxx>
using ::com::sun::star::beans::NamedValue;
using ::com::sun::star::beans::XPropertySet;
using ::com::sun::star::drawing::XShape;
using namespace ::com::sun::star::animations;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::container;
using namespace ::com::sun::star::presentation;
using namespace ::com::sun::star::uno;
namespace oox::core
{
namespace
{
bool isValidTarget(const Any& rTarget)
{
Reference<XShape> xShape;
if ((rTarget >>= xShape) && xShape.is())
return true;
ParagraphTarget aParagraphTarget;
return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
}
bool IsAudioURL(const OUString& rURL)
{
return rURL.endsWithIgnoreAsciiCase(".wav") || rURL.endsWithIgnoreAsciiCase(".m4a");
}
/// Returns if rURL has an extension which is a video format.
bool IsVideoURL(const OUString& rURL) { return rURL.endsWithIgnoreAsciiCase(".mp4"); }
}
NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
bool bIsIterateChild)
: mxNode(xNode)
, mbMainSeqChild(bMainSeqChild)
, mbValid(true)
, mnEffectNodeType(-1)
, mnEffectPresetClass(css::presentation::EffectPresetClass::CUSTOM)
{
assert(xNode.is());
initUserData();
initValid(initChildNodes(), bIsIterateChild);
}
void NodeContext::initUserData()
{
assert(mxNode.is());
Sequence<NamedValue> aUserData = mxNode->getUserData();
for (const NamedValue& rProp : aUserData)
{
if (rProp.Name == "node-type")
{
rProp.Value >>= mnEffectNodeType;
}
else if (rProp.Name == "preset-class")
{
rProp.Value >>= mnEffectPresetClass;
}
else if (rProp.Name == "preset-id")
{
rProp.Value >>= msEffectPresetId;
}
else if (rProp.Name == "preset-sub-type")
{
rProp.Value >>= msEffectPresetSubType;
}
}
}
void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
{
sal_Int16 nType = mxNode->getType();
if (nType == AnimationNodeType::ITERATE)
{
Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
&& !maChildNodes.empty();
}
else if (nType == AnimationNodeType::COMMAND)
{
Reference<XCommand> xCommand(mxNode, UNO_QUERY);
mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
}
else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
{
mbValid = bHasValidChild;
}
else if (nType == AnimationNodeType::AUDIO)
{
Reference<XAudio> xAudio(mxNode, UNO_QUERY);
OUString sURL;
Reference<XShape> xShape;
mbValid = false;
if (xAudio.is())
{
if (xAudio->getSource() >>= sURL)
{
mbValid = IsAudioURL(sURL);
}
else if (xAudio->getSource() >>= xShape)
{
Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
bool bHasMediaURL
= xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sURL))
{
mbValid = IsAudioURL(sURL) || IsVideoURL(sURL);
}
}
}
}
else
{
Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
}
}
bool NodeContext::initChildNodes()
{
bool bValid = false;
Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
if (xEnumerationAccess.is())
{
Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
if (xEnumeration.is())
{
while (xEnumeration->hasMoreElements())
{
Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
if (xChildNode.is())
{
auto pChildContext
= std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
if (pChildContext->isValid())
bValid = true;
maChildNodes.push_back(std::move(pChildContext));
}
}
}
}
return bValid;
}
const Reference<XAnimationNode>& NodeContext::getNodeForCondition() const
{
const bool bParent
= (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
return rNode;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View file

@ -0,0 +1,59 @@
/* -*- 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/.
*/
#pragma once
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/animations/XAnimationNode.hpp>
#include <vector>
namespace oox::core
{
class NodeContext;
typedef std::unique_ptr<NodeContext> NodeContextPtr;
class NodeContext
{
const css::uno::Reference<css::animations::XAnimationNode> mxNode;
const bool mbMainSeqChild;
std::vector<NodeContextPtr> maChildNodes;
// if the node has valid target or contains at least one valid target.
bool mbValid;
// Attributes initialized from mxNode->getUserData().
sal_Int16 mnEffectNodeType;
sal_Int16 mnEffectPresetClass;
OUString msEffectPresetId;
OUString msEffectPresetSubType;
/// constructor helper for initializing user data.
void initUserData();
/// constructor helper to initialize maChildNodes.
/// return true if at least one childnode is valid.
bool initChildNodes();
/// constructor helper to initialize mbValid
void initValid(bool bHasValidChild, bool bIsIterateChild);
public:
NodeContext(const css::uno::Reference<css::animations::XAnimationNode>& xNode,
bool bMainSeqChild, bool bIsIterateChild);
const css::uno::Reference<css::animations::XAnimationNode>& getNode() const { return mxNode; }
bool isMainSeqChild() const { return mbMainSeqChild; }
sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
const OUString& getEffectPresetId() const { return msEffectPresetId; }
const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
bool isValid() const { return mbValid; }
const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
const css::uno::Reference<css::animations::XAnimationNode>& getNodeForCondition() const;
};
}

View file

@ -60,7 +60,7 @@
#include "pptexanimations.hxx"
#include "pptx-animations.hxx"
#include "pptx-animations-cond.hxx"
#include "../ppt/pptanimations.hxx"
#include "pptx-animations-nodectx.hxx"
using namespace ::com::sun::star;
using namespace ::com::sun::star::animations;
@ -307,18 +307,6 @@ void WriteAnimationAttributeName(const FSHelperPtr& pFS, const OUString& rAttrib
pFS->endElementNS(XML_p, XML_attrNameLst);
}
bool isValidTarget(const Any& rTarget)
{
Reference<XShape> xShape;
if ((rTarget >>= xShape) && xShape.is())
return true;
ParagraphTarget aParagraphTarget;
return (rTarget >>= aParagraphTarget) && aParagraphTarget.Shape.is();
}
/// extract ooxml node type from a XAnimationNode.
sal_Int32 extractNodeType(const Reference<XAnimationNode>& rXNode)
{
@ -490,48 +478,6 @@ const char* convertTextAnimationType(sal_Int16 nType)
return sType;
}
class NodeContext;
typedef std::unique_ptr<NodeContext> NodeContextPtr;
class NodeContext
{
const Reference<XAnimationNode> mxNode;
const bool mbMainSeqChild;
std::vector<NodeContextPtr> maChildNodes;
// if the node has valid target or contains at least one valid target.
bool mbValid;
// Attributes initialized from mxNode->getUserData().
sal_Int16 mnEffectNodeType;
sal_Int16 mnEffectPresetClass;
OUString msEffectPresetId;
OUString msEffectPresetSubType;
/// constructor helper for initializing user data.
void initUserData();
/// constructor helper to initialize maChildNodes.
/// return true if at least one childnode is valid.
bool initChildNodes();
/// constructor helper to initialize mbValid
void initValid(bool bHasValidChild, bool bIsIterateChild);
public:
NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild, bool bIsIterateChild);
const Reference<XAnimationNode>& getNode() const { return mxNode; }
bool isMainSeqChild() const { return mbMainSeqChild; }
sal_Int16 getEffectNodeType() const { return mnEffectNodeType; }
sal_Int16 getEffectPresetClass() const { return mnEffectPresetClass; }
const OUString& getEffectPresetId() const { return msEffectPresetId; }
const OUString& getEffectPresetSubType() const { return msEffectPresetSubType; }
bool isValid() const { return mbValid; }
const std::vector<NodeContextPtr>& getChildNodes() const { return maChildNodes; };
const Reference<XAnimationNode>& getNodeForCondition() const;
};
class PPTXAnimationExport
{
void WriteAnimationNode(const NodeContextPtr& pContext);
@ -952,7 +898,7 @@ void PPTXAnimationExport::WriteAnimationNodeCommonPropsStart()
sDuration = OString::number(static_cast<sal_Int32>(fDuration * 1000.0));
sal_uInt32 nPresetClass = mpContext->getEffectPresetClass();
if (nPresetClass != DFF_ANIM_PRESS_CLASS_USER_DEFINED)
if (nPresetClass != EffectPresetClass::CUSTOM)
pPresetClass = convertEffectPresetClass(nPresetClass);
sal_uInt32 nPresetId = 0;
@ -1317,130 +1263,4 @@ sal_Int32 PPTXAnimationExport::GetAnimationNodeId(const Reference<XAnimationNode
return nId;
}
NodeContext::NodeContext(const Reference<XAnimationNode>& xNode, bool bMainSeqChild,
bool bIsIterateChild)
: mxNode(xNode)
, mbMainSeqChild(bMainSeqChild)
, mbValid(true)
, mnEffectNodeType(-1)
, mnEffectPresetClass(DFF_ANIM_PRESS_CLASS_USER_DEFINED)
{
assert(xNode.is());
initUserData();
initValid(initChildNodes(), bIsIterateChild);
}
void NodeContext::initUserData()
{
assert(mxNode.is());
Sequence<NamedValue> aUserData = mxNode->getUserData();
const Any* aIndexedData[DFF_ANIM_PROPERTY_ID_COUNT];
AnimationExporter::GetUserData(aUserData, aIndexedData, sizeof(aIndexedData));
const Any* pAny = aIndexedData[DFF_ANIM_NODE_TYPE];
if (pAny)
*pAny >>= mnEffectNodeType;
pAny = aIndexedData[DFF_ANIM_PRESET_CLASS];
if (pAny)
*pAny >>= mnEffectPresetClass;
pAny = aIndexedData[DFF_ANIM_PRESET_ID];
if (pAny)
*pAny >>= msEffectPresetId;
pAny = aIndexedData[DFF_ANIM_PRESET_SUB_TYPE];
if (pAny)
*pAny >>= msEffectPresetSubType;
}
void NodeContext::initValid(bool bHasValidChild, bool bIsIterateChild)
{
sal_Int16 nType = mxNode->getType();
if (nType == AnimationNodeType::ITERATE)
{
Reference<XIterateContainer> xIterate(mxNode, UNO_QUERY);
mbValid = xIterate.is() && (bIsIterateChild || isValidTarget(xIterate->getTarget()))
&& !maChildNodes.empty();
}
else if (nType == AnimationNodeType::COMMAND)
{
Reference<XCommand> xCommand(mxNode, UNO_QUERY);
mbValid = xCommand.is() && (bIsIterateChild || isValidTarget(xCommand->getTarget()));
}
else if (nType == AnimationNodeType::PAR || nType == AnimationNodeType::SEQ)
{
mbValid = bHasValidChild;
}
else if (nType == AnimationNodeType::AUDIO)
{
Reference<XAudio> xAudio(mxNode, UNO_QUERY);
OUString sURL;
uno::Reference<drawing::XShape> xShape;
mbValid = false;
if (xAudio.is())
{
if (xAudio->getSource() >>= sURL)
{
mbValid = IsAudioURL(sURL);
}
else if (xAudio->getSource() >>= xShape)
{
uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
bool bHasMediaURL
= xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL");
if (bHasMediaURL && (xShapeProps->getPropertyValue("MediaURL") >>= sURL))
{
mbValid = IsAudioURL(sURL) || IsVideoURL(sURL);
}
}
}
}
else
{
Reference<XAnimate> xAnimate(mxNode, UNO_QUERY);
mbValid = xAnimate.is() && (bIsIterateChild || isValidTarget(xAnimate->getTarget()));
}
}
bool NodeContext::initChildNodes()
{
bool bValid = false;
Reference<XEnumerationAccess> xEnumerationAccess(mxNode, UNO_QUERY);
if (xEnumerationAccess.is())
{
Reference<XEnumeration> xEnumeration = xEnumerationAccess->createEnumeration();
bool bIsMainSeq = mnEffectNodeType == EffectNodeType::MAIN_SEQUENCE;
bool bIsIterateChild = mxNode->getType() == AnimationNodeType::ITERATE;
if (xEnumeration.is())
{
while (xEnumeration->hasMoreElements())
{
Reference<XAnimationNode> xChildNode(xEnumeration->nextElement(), UNO_QUERY);
if (xChildNode.is())
{
auto pChildContext
= std::make_unique<NodeContext>(xChildNode, bIsMainSeq, bIsIterateChild);
if (pChildContext->isValid())
bValid = true;
maChildNodes.push_back(std::move(pChildContext));
}
}
}
}
return bValid;
}
const Reference<XAnimationNode>& NodeContext::getNodeForCondition() const
{
const bool bParent
= (mnEffectNodeType != EffectNodeType::INTERACTIVE_SEQUENCE || maChildNodes.empty());
const Reference<XAnimationNode>& rNode = bParent ? mxNode : maChildNodes[0]->getNode();
return rNode;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */